001: package simpleorm.core;
002:
003: import simpleorm.properties.*;
004:
005: /*
006: * Copyright (c) 2002 Southern Cross Software Limited (SCSQ). All rights
007: * reserved. See COPYRIGHT.txt included in this distribution.
008: */
009:
010: /** This interface contains all the SProperties constants used in
011: SimpleORM. Properties are a general way to attach extra information
012: to SRecordMetas and SFieldMetas. They are usually used as follows:-<p>
013: <xmp>
014: public static final SFieldObject TSTAMP_OBJ =
015: new SFieldObject(meta, "TSTAMP_OBJ",
016: SDATA_TYPE.pvalue("TIMESTAMP"));
017:
018: public static final SFieldString DATA_ID =
019: new SFieldString(meta, "DATA_ID", 10, SFD_PRIMARY_KEY);
020: </xmp>
021:
022: Each of the <code>SField*</code> initializers allows 0, 1, 2 or an
023: array of <code>SPropertyValues</code> to be passed as trailing
024: parameters. Each of these contains an SProperty and a value for that
025: property. Thus the first example adds a property
026: <code>SDATA_TYPE</code> to the <code>TSTAMP_OBJ</code> field with
027: value <code>"TIMESTAMP"</code>.<p>
028:
029: As a convenience the <code>SFD_</code> constants contain precreated
030: <code>SPropertyValues</code> for simple boolean properties. So the
031: second example is just a short cut for:-<p>
032:
033: <xmp>
034: public static final SFieldString DATA_ID =
035: new SFieldString(meta, "DATA_ID", 10,
036: SPRIMARY_KEY.pvalue(Boolean.TRUE));
037: </xmp>
038:
039: (Due to a bug in Javadoc (1.3 at least) anonymous classes cannot be used to initiate static constants.)<p> */
040:
041: public interface SSimpleORMProperties {
042:
043: /** The array of fields with in an SRecordMeta. */
044: static final SProperty SFIELD_METAS = new SPropertySFieldMetas();
045:
046: public static class SPropertySFieldMetas extends SProperty {
047: SPropertySFieldMetas() {
048: super ("SFieldMetas");
049: }
050:
051: protected Object theValue(SPropertyMap map) {
052: SRecordMeta rec = (SRecordMeta) map;
053: return rec.sFieldMetas.toArray(new SFieldMeta[0]);
054: }
055: }
056:
057: /** Map of all fields in an SRecordMeta. Same elements as
058: <code>SFIELD_METAS</code>, but a HashMap instead of an array,
059: keyed by the SFIELD_NAME name.<p>
060:
061: Normally just use <code>SRecordMeta.getField(name)<code> to
062: retrieve fields by name. */
063: static final SProperty SFIELD_MAP = new SPropertySFieldMap();
064:
065: public static class SPropertySFieldMap extends SProperty {
066: SPropertySFieldMap() {
067: super ("SFieldMap");
068: ;
069: }
070:
071: protected Object theValue(SPropertyMap map) {
072: SRecordMeta rec = (SRecordMeta) map;
073: return rec.fieldMap;
074: }
075: }
076:
077: /** Arbitrary field name to be used by applications. Defaults to
078: column name or to Column name or prefix or Referenced table name
079: for references. */
080: static final SProperty SFIELD_NAME = new SProperty("SFieldName");
081:
082: /** The record that an SFieldMeta is associated with. */
083: static final SProperty SRECORD_META = new SPropertySRecordMeta();
084:
085: public static class SPropertySRecordMeta extends SProperty {
086: SPropertySRecordMeta() {
087: super ("SRecordMeta");
088: }
089:
090: protected Object theValue(SPropertyMap map) {
091: SFieldMeta fld = (SFieldMeta) map;
092: return fld.sRecordMeta;
093: }
094: }
095:
096: /** Index into <code>SFIELD_METAS</code> of an sFieldMeta.
097: ie. <code>field.SRECORD_META.SFIELD_METAS[field.SFIELD_INDEX] ==
098: field</code>. */
099: static final SProperty SFIELD_INDEX = new SPropertySFieldIndex();
100:
101: public static class SPropertySFieldIndex extends SProperty {
102: SPropertySFieldIndex() {
103: super ("SFieldIndex");
104: }
105:
106: protected Object theValue(SPropertyMap map) {
107: SFieldMeta fld = (SFieldMeta) map;
108: return SJSharp.newInteger(fld.fieldIndex);
109: }
110: }
111:
112: /** The table name of this record OR field. */
113: static SProperty STABLE_NAME = new SPropertySTableName();
114:
115: public static class SPropertySTableName extends SProperty {
116: SPropertySTableName() {
117: super ("STableName");
118: }
119:
120: protected Object defaultValue(SPropertyMap map) {
121: SPropertyMap rec = (SPropertyMap) map
122: .getProperty(SRECORD_META);
123: return rec.getProperty(STABLE_NAME);
124: }
125: };
126:
127: /** Name of the SQL column. */
128: static final SProperty SCOLUMN_NAME = new SProperty("SColumnName");
129:
130: /** Query fragment to select value. May be a subselect.
131: Normally also SUNQUERIED. Never updates.*/
132: static final SProperty SCOLUMN_QUERY = new SProperty("SColumnQuery");
133:
134: /** The SQL data type of the column. For the generic driver this
135: corresponds to the actual type used in the Create Table
136: statement.
137: Warning, these may be mapped by the SDrivers to try to overcome
138: type incompatibilities.
139: */
140: static final SProperty SDATA_TYPE = new SPropertySDataType();
141:
142: public static class SPropertySDataType extends SProperty {
143: SPropertySDataType() {
144: super ("SDataType");
145: }
146:
147: protected Object defaultValue(SPropertyMap map) {
148: return ((SFieldMeta) map).defaultDataType();
149: }
150: }
151:
152: /** The parameter to the Varchar(...) data type on the Create Table
153: statement. Note that it is normally the number of bytes, not the
154: number of characters (in UTF-8, say). It is a meaningless number,
155: but most databases demand it. Postgresql does not, and it is not
156: used in that case. */
157: static final SProperty SBYTE_SIZE = new SProperty("SByteSize");
158:
159: /** The precission and scale of Numerics for BigDecimal. Used to
160: generate <code>NUMERIC(precission, scale) in CREATE TABLE</code>
161: statements.*/
162: static final SProperty SDECIMAL_PRECISION = new SProperty(
163: "SDecimalPrecision");
164: static final SProperty SDECIMAL_SCALE = new SProperty(
165: "SDecimalScale");
166:
167: /** Specifies that the String datatype is to be represented as a
168: CHAR and not a VARCHAR. */
169: static final SProperty SSTRING_CHAR = new SProperty("SStringChar");
170: static final SPropertyValue SFD_STRING_CHAR = new SPropertyValue(
171: SSTRING_CHAR);
172:
173: /** Indicates which are the primary key field(s).
174: Every record must have a primary key. */
175: static final SProperty SPRIMARY_KEY = new SProperty("SPrimaryKey");
176: static final SPropertyValue SFD_PRIMARY_KEY = new SPropertyValue(
177: SPRIMARY_KEY);
178:
179: /** SFieldReference property that suppresses the generation of
180: Foreign Key constraint DDL. Defaults from Record and thence Connection. */
181: static final SProperty SNO_FOREIGN_KEY = new SPropertyNoForeignKey();
182: static final SPropertyValue SFD_NO_FOREIGN_KEY = new SPropertyValue(
183: SNO_FOREIGN_KEY);
184:
185: public static class SPropertyNoForeignKey extends SProperty {
186: SPropertyNoForeignKey() {
187: super ("SNoForeignKey");
188: }
189:
190: protected Object defaultValue(SPropertyMap map) {
191: if (map instanceof SFieldMeta) {
192: SPropertyMap rec = (SPropertyMap) map
193: .getProperty(SRECORD_META);
194: return rec.getProperty(SNO_FOREIGN_KEY);
195: } else if (map instanceof SRecordMeta
196: && SConnection.getConnection() != null)
197: return SConnection.getConnection().getProperty(
198: SNO_FOREIGN_KEY);
199: else
200: return null;
201: }
202: };
203:
204: /** If Field A.SFIELD_REFERENCE = Field B then B is a
205: SFieldReference field and A forms a part of that reference.
206: Eg. if B = Employee.Department, A=Employee.Dept_Id.*/
207: static final SProperty SFIELD_REFERENCE = new SPropertySFieldReference();
208:
209: public static class SPropertySFieldReference extends SProperty {
210: SPropertySFieldReference() {
211: super ("SFieldReference");
212: }
213:
214: protected Object theValue(SPropertyMap map) {
215: SFieldMeta fld = (SFieldMeta) map;
216: return fld.sFieldReference;
217: }
218: }
219:
220: //## Should expose the entire internal schema though properties like this.
221:
222: /** Normally only top level foreign keys are generated. So
223: PayrollDetail to Payroll is foreign key is normally generated,
224: but not the nested PayrollDetail to Employee. However, this
225: property can be used to enable inner foreign keys to be
226: generated as well. (Rarely used in practice.) */
227: static final SProperty SINNER_FOREIGN_KEY = new SPropertyInnerForeignKey();
228: static final SPropertyValue SFD_INNER_FOREIGN_KEY = new SPropertyValue(
229: SINNER_FOREIGN_KEY);
230:
231: public static class SPropertyInnerForeignKey extends SProperty {
232: SPropertyInnerForeignKey() {
233: super ("SInnerForeignKey");
234: }
235:
236: protected Object defaultValue(SPropertyMap map) {
237: SFieldMeta ref = (SFieldMeta) map
238: .getProperty(SFIELD_REFERENCE);
239: return ref != null ? ref.getProperty(SINNER_FOREIGN_KEY)
240: : null;
241: }
242: };
243:
244: /** Only "Descriptive" fields (eg. Name) will be queried if
245: <code>SQY_DESCRIPTIVE</code> is specified. */
246: static final SProperty SDESCRIPTIVE = new SProperty("SDescriptive");
247: static final SPropertyValue SFD_DESCRIPTIVE = new SPropertyValue(
248: SDESCRIPTIVE);
249:
250: /** <code>SUNQUERIED</code> fields are not normally retrieved by
251: queries unless the <code>SQY_UNQUERIED</code> flag is specified
252: on the query. Typically large, rarely used fields. */
253: static final SProperty SUNQUERIED = new SProperty("SUnqueried");
254: static final SPropertyValue SFD_UNQUERIED = new SPropertyValue(
255: SUNQUERIED);
256:
257: /** The field must not be "empty" when the record is flushed. It may
258: temporarily be empty in the meantime.<p>
259:
260: In order to avoid the horrible SQL NULL semantics, some
261: databases prefer to store empty string values as <code>""</code>
262: rather than <code>NULL</code>s (eg. Sybase, MSSQL). For now
263: <code>SMANDATORY</code> just means <code>NOT NULL</code> in
264: create table statements. A java value of <code>""</code>
265: produces SQL <code>""</code>, a java <code>null</code> produces
266: sql <code>null</code>.<p>
267:
268: ### Additional null semantics will be provided later that unify
269: <code>""</code> and <code>null</code> to provide output
270: appropriate for the database used. This will make it easier to
271: write database independent code, and avoid horrible bugs when
272: the two are confused.<p>
273:
274: @see SRecordInstance#isEmpty
275: */
276: static final SProperty SMANDATORY = new SProperty("SMandatory");
277: static final SPropertyValue SFD_MANDATORY = new SPropertyValue(
278: SMANDATORY);
279:
280: /** A generated primary key column.
281: * The value must be an SGenerator subtype.
282: *
283: See GeneratedKeyTest.
284: */
285: static final SProperty SGENERATED_KEY = new SPropertySGeneratedKey();
286:
287: public static class SPropertySGeneratedKey extends SProperty {
288: SPropertySGeneratedKey() {
289: super ("SGeneratedKey");
290: }
291:
292: protected void validate(SPropertyMap map, Object value) {
293: if (!(value instanceof SGenerator))
294: throw new RuntimeException("SGeneratedKey " + value
295: + " is not an SGenerator");
296: }
297: }
298:
299: /** Name of the sequence to use for the generated key for databases
300: that support them (eg. Postgresql). Defaults to
301: tablename_SEQ. Boolean.FALSE is a special value that causes
302: the default Select Max algoritm to be used. */
303: static SProperty SSEQUENCE_NAME = new SPropertySSequenceName();
304:
305: public static class SPropertySSequenceName extends SProperty {
306: SPropertySSequenceName() {
307: super ("SSequenceName");
308: }
309:
310: protected Object defaultValue(SPropertyMap map) {
311: String tname = map.getString(STABLE_NAME);
312: return tname + "_SEQ";
313: }
314: }
315:
316: /** Suppresses this column being used as a foreign key component.
317: Must be used for database types that cannot be used in WHERE
318: clauses such as Oracle's long type. */
319: static final SProperty SOPTIMISTIC_UNCHECKED = new SProperty(
320: "SOptimisticUnchecked");
321: static final SPropertyValue SFD_OPTIMISTIC_UNCHECKED = new SPropertyValue(
322: SOPTIMISTIC_UNCHECKED);
323:
324: /** Extra text that is appended blindly after the DDL
325: <code>CREATE TABLE</code> column type information but before the
326: ",". Can be used for database specific tuning, check clauses
327: etc.*/
328: static final SProperty SEXTRA_COLUMN_DDL = new SProperty(
329: "SExtraColumnDDL");
330:
331: /** Extra text that is appended blindly at the very end of
332: the DDL <code>CREATE TABLE (..., PRIMARY KEY...</code> but
333: before the closing ")". Can be used for database specific
334: tuning, check clauses etc. This text usually begins with a ",".*/
335: static final SProperty SEXTRA_TABLE_DDL = new SProperty(
336: "SExtraTableDDL");
337:
338: /** Extra text that is appended blindly at the very end of a foreign
339: key definition. A typical value is " ON DELETE CASCADE". (No
340: attempt is made by SimpleORM to keep the cache consistent with
341: changes to the database made in this way.)
342: */
343: static final SProperty SEXTRA_FKEY_DDL = new SProperty(
344: "SExtraFKeyDDL");
345:
346: }
|