Browse Source

Documentation. EnumType default is NAME.

tags/v0.6.3
James Moger 13 years ago
parent
commit
35973f16d6

+ 76
- 16
docs/01_model_classes.mkd View File

Alternatively, model classes can be automatically generated by iciql using the model generation tool. Please see the [tools](tools.html) page for details. Alternatively, model classes can be automatically generated by iciql using the model generation tool. Please see the [tools](tools.html) page for details.
### Supported Data Types
<table>
### Configuration Requirements and Limitations
1. Your model class **must** provide a public default constructor.
2. Only the specified types are supported. Other types such as arrays and custom types are not supported.
3. Triggers, views, and other advanced database features are not supported.
### Fully Supported Data Types
The following data types can be used for all iciql expressions.
<table>
<tr><th colspan="2">All Databases</th></tr>
<tr><td>java.lang.String</td> <tr><td>java.lang.String</td>
<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*</td></tr> <td>VARCHAR *(length > 0)* or TEXT *(length == 0)*</td></tr>
<tr><td>java.util.Date</td> <tr><td>java.util.Date</td>
<td>TIMESTAMP</td></tr> <td>TIMESTAMP</td></tr>
<tr><td>byte []</td>
<td>BLOB</td></tr>
<tr><td>java.lang.Enum.name()</td>
<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*<br/>*EnumType.STRING*</td></tr>
<tr><td>java.lang.Enum.name()<br/>*default type*</td>
<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*<br/>*EnumType.NAME*</td></tr>
<tr><td>java.lang.Enum.ordinal()</td> <tr><td>java.lang.Enum.ordinal()</td>
<td>INT<br/>*EnumType.ORDINAL*</td></tr> <td>INT<br/>*EnumType.ORDINAL*</td></tr>
<tr><td>java.lang.Enum implements<br/>*com.iciql.Iciql.EnumId.enumId()*</td> <tr><td>java.lang.Enum implements<br/>*com.iciql.Iciql.EnumId.enumId()*</td>
<td>INT<br/>*EnumType.ENUMID*</td></tr> <td>INT<br/>*EnumType.ENUMID*</td></tr>
<tr><th colspan="2">H2 Databases</th></tr>
<tr><td>java.util.UUID</td>
<td>UUID</td><tr/>
</table> </table>
**NOTE:**<br/> **NOTE:**<br/>
The reverse lookup used for model generation, SQL type -> Java type, contains more mappings.<br/> The reverse lookup used for model generation, SQL type -> Java type, contains more mappings.<br/>
Please consult the `com.iciql.ModelUtils` class for details. Please consult the `com.iciql.ModelUtils` class for details.
### Unsupported Types
- Java primitives (use their object counterparts instead)
- array types
- custom types
### Partially Supported Data Types
The following data types can be mapped to columns for all general statements <u>BUT</u> these field types may **not** be used to specify **compile-time** *clauses or constraints*.
<table>
<tr><td>byte []</td>
<td>BLOB</td></tr>
<tr><td>boolean</td>
<td>BIT</td></tr>
<tr><td>byte</td>
<td>TINYINT</td></tr>
<tr><td>short</td>
<td>SMALLINT</td></tr>
<tr><td>int</td>
<td>INT</td></tr>
<tr><td>long</td>
<td>BIGINT</td></tr>
<tr><td>float</td>
<td>REAL</td></tr>
<tr><td>double</td>
<td>DOUBLE</td></tr>
</table>
### Configuration Rules
1. field mappings must be Objects not primitives
2. the model class must have a default public constructor
#### Partially Supported Data Types Example
%BEGINCODE%
class Primitives {
@IQColumn(primaryKey = true)
int id;
@IQColumn
String name;
public Primitives() {
}
public Primitives(int id, String name) {
this.id = id;
this.name = name;
}
}
Primitives p = new Primitives();
// the following expressions compile, but will throw iciql runtime exceptions
db.from(p).where(p.id).is(100).selectFirst();
db.from(p).where(p.id).atLeast(10).select();
// the following expressions will work as expected
db.from(p).select();
db.from(p).where("id = ?", 100).selectFirst();
db.from(p).where("id >= ?", 10).select();
db.insert(new Primitives(150, "test"));
db.update(new Primitives(150, "modified"));
db.delete(new Primitives(150, "test"));
%ENDCODE%
### Configuration Limitations
Triggers, views, and other advanced database features are unimplemented.
## Annotation Configuration ## Annotation Configuration
The recommended approach to setup a model class is to annotate the class and field declarations. The recommended approach to setup a model class is to annotate the class and field declarations.

+ 1
- 1
docs/02_table_versioning.mkd View File

### How does it work? ### How does it work?
If you choose to use versioning, iciql will maintain a table within your database named *_iq_versions* which is defined as: If you choose to use versioning, iciql will maintain a table within your database named *_iq_versions* which is defined as:
CREATE TABLE _IQ_VERSIONS(SCHEMANAME TEXT NOT NULL, TABLENAME TEXT NOT NULL, VERSION INT NOT NULL)
CREATE TABLE _IQ_VERSIONS(SCHEMANAME VARCHAR(255) NOT NULL, TABLENAME VARCHAR(255) NOT NULL, VERSION INT NOT NULL)
This database table is automatically created if and only if at least one of your model classes specifies a *version* > 0. This database table is automatically created if and only if at least one of your model classes specifies a *version* > 0.

+ 1
- 1
docs/02_usage.mkd View File

#### Db.executeQuery Approaches #### Db.executeQuery Approaches
There may be times when the hybrid approach is still too restrictive and you'd prefer to write straight SQL. You can do that too and use iciql to build objects from your ResultSet, but be careful: There may be times when the hybrid approach is still too restrictive and you'd prefer to write straight SQL. You can do that too and use iciql to build objects from your ResultSet, but be careful:
1. Make sure to _select *_ in your query otherwise db.bindResultSet() will throw a RuntimeException
1. Make sure to _select *_ in your query otherwise db.buildObjects() will throw a RuntimeException
2. There is no model class type checking nor field type checking. 2. There is no model class type checking nor field type checking.
%BEGINCODE% %BEGINCODE%

+ 13
- 4
docs/05_releases.mkd View File

## Release History ## Release History
### Current Release ### Current Release
**%VERSION%** ([zip](http://code.google.com/p/iciql/downloads/detail?name=%ZIP%)|[jar](http://code.google.com/p/iciql/downloads/detail?name=%JAR%)) &nbsp; *released %BUILDDATE%* **%VERSION%** ([zip](http://code.google.com/p/iciql/downloads/detail?name=%ZIP%)|[jar](http://code.google.com/p/iciql/downloads/detail?name=%JAR%)) &nbsp; *released %BUILDDATE%*
- api change release (API v3)
- finished enum support (issue 4)
- added UUID type support (H2 databases only)
- added partial primitives support *(primitives may not be used for compile-time condition clauses)*
- added *between(A y).and(A z)* condition syntax
### Older Releases
**0.6.2** &nbsp; *released 2011-08-05*
- api change release (API v2) - api change release (API v2)
- fix to versioning to support H2 1.3.158+ - fix to versioning to support H2 1.3.158+
- added BLOB support (issue 1) - added BLOB support (issue 1)
%ENDCODE% %ENDCODE%
- @IQColumn(maxLength=20) -> @IQColumn(length=20) - @IQColumn(maxLength=20) -> @IQColumn(length=20)
- @IQColumn(trimString=true) -> @IQColumn(trim=true) - @IQColumn(trimString=true) -> @IQColumn(trim=true)
### Older Releases
**0.5.0** ([zip](http://code.google.com/p/iciql/downloads/detail?name=iciql-0.5.0.zip)|[jar](http://code.google.com/p/iciql/downloads/detail?name=iciql-0.5.0.jar)) &nbsp; *released 2011-08-03*
**0.5.0** &nbsp; *released 2011-08-03*
- initial release (API v1) - initial release (API v1)

+ 39
- 14
src/com/iciql/Iciql.java View File

* If a class is annotated with IQTable and at the same time implements Table, * If a class is annotated with IQTable and at the same time implements Table,
* the define() method is not called. * the define() method is not called.
* <p> * <p>
* Supported data types:
* Fully Supported Data Types:
* <table> * <table>
* <tr><th colspan="2">All Databases</th></tr>
* <tr> * <tr>
* <td>java.lang.String</td> * <td>java.lang.String</td>
* <td>VARCHAR (length > 0) or TEXT (length == 0)</td> * <td>VARCHAR (length > 0) or TEXT (length == 0)</td>
* <td>TIMESTAMP</td> * <td>TIMESTAMP</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>byte []</td>
* <td>BLOB</td>
* </tr>
* <tr>
* <td>java.lang.Enum.name()</td> * <td>java.lang.Enum.name()</td>
* <td>VARCHAR (length > 0) or TEXT (length == 0)<br/> * <td>VARCHAR (length > 0) or TEXT (length == 0)<br/>
* EnumType.STRING</td>
* EnumType.NAME</td>
* </tr> * </tr>
* <tr> * <tr>
* <td>java.lang.Enum.ordinal()</td> * <td>java.lang.Enum.ordinal()</td>
* <td>INT<br/> * <td>INT<br/>
* EnumType.ENUMID</td> * EnumType.ENUMID</td>
* </tr> * </tr>
* <tr><th colspan="2">H2 Databases</th></tr>
* <tr>
* <td>java.util.UUID</td>
* <td>UUID</td>
* </tr> * </tr>
* </table> * </table>
* <p> * <p>
* Unsupported data types: primitives, Array Types, and custom types.
* Partially Supported Data Types:
* <p>
* The following data types can be mapped to columns for all general statements
* BUT these field types may not be used to specify compile-time clauses or
* constraints.
* <table>
* <tr><td>byte []</td>
* <td>BLOB</td></tr>
* <tr><td>boolean</td>
* <td>BIT</td></tr>
* <tr><td>byte</td>
* <td>TINYINT</td></tr>
* <tr><td>short</td>
* <td>SMALLINT</td></tr>
* <tr><td>int</td>
* <td>INT</td></tr>
* <tr><td>long</td>
* <td>BIGINT</td></tr>
* <tr><td>float</td>
* <td>REAL</td></tr>
* <tr><td>double</td>
* <td>DOUBLE</td></tr>
* </table>
* <p> * <p>
* Table and field mapping: by default, the mapped table name is the class name * Table and field mapping: by default, the mapped table name is the class name
* and the public fields are reflectively mapped, by their name, to columns. As * and the public fields are reflectively mapped, by their name, to columns. As
* Enumeration representing how to map a java.lang.Enum to a column. * Enumeration representing how to map a java.lang.Enum to a column.
* <p> * <p>
* <ul> * <ul>
* <li>STRING - name() : string
* <li>NAME - name() : string
* <li>ORDINAL - ordinal() : int * <li>ORDINAL - ordinal() : int
* <li>ENUMID - enumId() : int * <li>ENUMID - enumId() : int
* </ul> * </ul>
* @see com.iciql.Iciql.EnumId interface * @see com.iciql.Iciql.EnumId interface
*/ */
public enum EnumType { public enum EnumType {
STRING, ORDINAL, ENUMID;
NAME, ORDINAL, ENUMID;
public static final EnumType DEFAULT_TYPE = NAME;
} }
/** /**
* be overridden for an individual field by specifying the IQEnum * be overridden for an individual field by specifying the IQEnum
* annotation. * annotation.
* <p> * <p>
* The default mapping is by STRING.
* The default mapping is by NAME.
* *
* <pre> * <pre>
* IQEnum(EnumType.STRING)
* IQEnum(EnumType.NAME)
* </pre> * </pre>
* *
* A string mapping will generate either a VARCHAR, if IQColumn.length >
* 0 or a TEXT column if IQColumn.length == 0
* A string mapping will generate either a VARCHAR, if IQColumn.length > 0
* or a TEXT column if IQColumn.length == 0
* *
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.TYPE }) @Target({ ElementType.FIELD, ElementType.TYPE })
public @interface IQEnum { public @interface IQEnum {
EnumType value() default EnumType.STRING;
EnumType value() default EnumType.NAME;
} }
/** /**

+ 6
- 7
src/com/iciql/ModelUtils.java View File

import java.util.UUID; import java.util.UUID;
import java.util.regex.Pattern; import java.util.regex.Pattern;


import com.iciql.Iciql.EnumType;
import com.iciql.TableDefinition.FieldDefinition; import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.util.StringUtils; import com.iciql.util.StringUtils;


static String getDataType(FieldDefinition fieldDef, boolean strictTypeMapping) { static String getDataType(FieldDefinition fieldDef, boolean strictTypeMapping) {
Class<?> fieldClass = fieldDef.field.getType(); Class<?> fieldClass = fieldDef.field.getType();
if (fieldClass.isEnum()) { if (fieldClass.isEnum()) {
if (fieldDef.enumType == null) {
throw new IciqlException(fieldDef.field.getName() + " enum field does not specify @IQEnum!");
}
switch (fieldDef.enumType) { switch (fieldDef.enumType) {
case STRING:
case ORDINAL:
case ENUMID:
return "INT";
case NAME:
default:
if (fieldDef.maxLength <= 0) { if (fieldDef.maxLength <= 0) {
return "TEXT"; return "TEXT";
} }
return "VARCHAR"; return "VARCHAR";
case ORDINAL:
case ENUMID:
return "INT";
} }
} }
if (SUPPORTED_TYPES.containsKey(fieldClass)) { if (SUPPORTED_TYPES.containsKey(fieldClass)) {

+ 2
- 1
src/com/iciql/TableDefinition.java View File

// configure Java -> SQL enum mapping // configure Java -> SQL enum mapping
if (f.getType().isEnum()) { if (f.getType().isEnum()) {
enumType = EnumType.DEFAULT_TYPE;
if (f.getType().isAnnotationPresent(IQEnum.class)) { if (f.getType().isAnnotationPresent(IQEnum.class)) {
// enum definition is annotated for all instances // enum definition is annotated for all instances
IQEnum iqenum = f.getType().getAnnotation(IQEnum.class); IQEnum iqenum = f.getType().getAnnotation(IQEnum.class);
// convert enumeration to INT or STRING // convert enumeration to INT or STRING
Enum<?> iqenum = (Enum<?>) value; Enum<?> iqenum = (Enum<?>) value;
switch (field.enumType) { switch (field.enumType) {
case STRING:
case NAME:
if (field.trimString && field.maxLength > 0) { if (field.trimString && field.maxLength > 0) {
if (iqenum.name().length() > field.maxLength) { if (iqenum.name().length() > field.maxLength) {
return iqenum.name().substring(0, field.maxLength); return iqenum.name().substring(0, field.maxLength);

+ 2
- 6
src/com/iciql/util/Utils.java View File

import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
return clazz.getEnumConstants()[0]; return clazz.getEnumConstants()[0];
} else if (clazz == java.util.UUID.class) { } else if (clazz == java.util.UUID.class) {
return (T) UUID.randomUUID(); return (T) UUID.randomUUID();
} else if (clazz == List.class) {
return (T) new ArrayList();
} }
try { try {
return clazz.newInstance(); return clazz.newInstance();
} }
public static Object convertEnum(Enum<?> o, EnumType type) { public static Object convertEnum(Enum<?> o, EnumType type) {
if (o == null || type == null) {
if (o == null) {
return null; return null;
} }
switch (type) { switch (type) {
} }
EnumId enumid = (EnumId) o; EnumId enumid = (EnumId) o;
return enumid.enumId(); return enumid.enumId();
case STRING:
case NAME:
default: default:
return o.name(); return o.name();
} }
if (targetType.isAssignableFrom(currentType)) { if (targetType.isAssignableFrom(currentType)) {
return o; return o;
} }
// convert from VARCHAR/TEXT/INT to Enum // convert from VARCHAR/TEXT/INT to Enum
Enum<?>[] values = (Enum[]) targetType.getEnumConstants(); Enum<?>[] values = (Enum[]) targetType.getEnumConstants();
if (Clob.class.isAssignableFrom(currentType)) { if (Clob.class.isAssignableFrom(currentType)) {

+ 1
- 1
tests/com/iciql/test/ModelsTest.java View File

true); true);
assertEquals(1, models.size()); assertEquals(1, models.size());
// a poor test, but a start // a poor test, but a start
assertEquals(1697, models.get(0).length());
assertEquals(1780, models.get(0).length());
} }


@Test @Test

+ 17
- 12
tests/com/iciql/test/PrimitivesTest.java View File

db.insert(model); db.insert(model);
PrimitivesModel p = new PrimitivesModel(); PrimitivesModel p = new PrimitivesModel();
// retrieve model and compare // retrieve model and compare
PrimitivesModel retrievedModel = db.from(p).selectFirst(); PrimitivesModel retrievedModel = db.from(p).selectFirst();
assertTrue(model.equivalentTo(retrievedModel)); assertTrue(model.equivalentTo(retrievedModel));
// retrieve with conditions and compare
// StatementLogger.activateConsoleLogger();
// retrievedModel = db.from(p).where(p.myLong).is(model.myLong).and(p.myInteger).is(model.myInteger)
// .selectFirst();
// assertTrue(model.equivalentTo(retrievedModel));
//
// // update myInteger and compare
// db.from(p).set(p.myInteger).to(10).where(p.myLong).is(model.myLong).update();
// retrievedModel = db.from(p).selectFirst();
// assertEquals(10, retrievedModel.myInteger);
retrievedModel = db.from(p).where("mylong = ? and myinteger = ?", model.myLong, model.myInteger)
.selectFirst();
assertTrue(model.equivalentTo(retrievedModel));
// retrieve with conditions and compare
// StatementLogger.activateConsoleLogger();
// retrievedModel =
// db.from(p).where(p.myLong).is(model.myLong).and(p.myInteger).is(model.myInteger)
// .selectFirst();
// assertTrue(model.equivalentTo(retrievedModel));
//
// // update myInteger and compare
// db.from(p).set(p.myInteger).to(10).where(p.myLong).is(model.myLong).update();
// retrievedModel = db.from(p).selectFirst();
// assertEquals(10, retrievedModel.myInteger);
db.close(); db.close();
} }

+ 1
- 1
tests/com/iciql/test/models/EnumModels.java View File

// override the enumtype to string // override the enumtype to string
// ensure that we specify a length so that the column is VARCHAR // ensure that we specify a length so that the column is VARCHAR
@IQEnum(EnumType.STRING)
@IQEnum(EnumType.NAME)
@IQColumn(length = 25) @IQColumn(length = 25)
private Tree tree; private Tree tree;

+ 7
- 1
tests/com/iciql/test/models/SupportedTypes.java View File

@IQColumn @IQColumn
private byte[] myBlob; private byte[] myBlob;


@IQEnum(EnumType.STRING)
// test default enum type NAME
@IQColumn(trim = true, length = 25)
private Flower myDefaultFlower;

@IQEnum(EnumType.NAME)
@IQColumn(trim = true, length = 25) @IQColumn(trim = true, length = 25)
private Flower myFavoriteFlower; private Flower myFavoriteFlower;


s.mySqlTime = new java.sql.Time(rand.nextLong()); s.mySqlTime = new java.sql.Time(rand.nextLong());
s.mySqlTimestamp = new java.sql.Timestamp(rand.nextLong()); s.mySqlTimestamp = new java.sql.Timestamp(rand.nextLong());
s.myBlob = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; s.myBlob = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
s.myDefaultFlower = Flower.DAFFODIL;
s.myFavoriteFlower = Flower.MUM; s.myFavoriteFlower = Flower.MUM;
s.myOtherFavoriteFlower = Flower.MARIGOLD; s.myOtherFavoriteFlower = Flower.MARIGOLD;
s.myFavoriteTree = Tree.BIRCH; s.myFavoriteTree = Tree.BIRCH;
same &= mySqlTime.toString().equals(s.mySqlTime.toString()); same &= mySqlTime.toString().equals(s.mySqlTime.toString());
same &= myString.equals(s.myString); same &= myString.equals(s.myString);
same &= compare(myBlob, s.myBlob); same &= compare(myBlob, s.myBlob);
same &= myDefaultFlower.equals(s.myDefaultFlower);
same &= myFavoriteFlower.equals(s.myFavoriteFlower); same &= myFavoriteFlower.equals(s.myFavoriteFlower);
same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower); same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower);
same &= myFavoriteTree.equals(s.myFavoriteTree); same &= myFavoriteTree.equals(s.myFavoriteTree);

Loading…
Cancel
Save