* @IQSchema(name="public") -> @IQSchema("public") * @IQDatabase(version=2) -> @IQVersion(2) * @IQTable(version=2) -> @IQVersion(2) * @IQIndex annotation simplified to be used for one index definition and expanded to specify index name * added @IQIndexes annotation to specify multiple IQIndex annotationstags/v0.6.0
@@ -64,8 +64,7 @@ Please consult the `com.iciql.ModelUtils` class for details. | |||
2. the model class must have a default public constructor | |||
### Configuration Limitations | |||
1. index names can not be specified | |||
2. triggers, views, and other advanced database features are unimplemented | |||
Triggers, views, and other advanced database features are unimplemented. | |||
## Annotation Configuration | |||
The recommended approach to setup a model class is to annotate the class and field declarations. | |||
@@ -89,7 +88,10 @@ import com.iciql.Iciql.IQIndex; | |||
import com.iciql.Iciql.IQTable; | |||
@IQTable | |||
@IQIndex(standard = {"productName", "category"}) | |||
@IQIndexes({ | |||
@IQIndex({"productName", "category"}), | |||
@IQIndex(name="nameindex", value="productName") | |||
}) | |||
public class Product { | |||
@IQColumn(primaryKey = true) |
@@ -3,9 +3,9 @@ | |||
Iciql supports an optional, simple versioning mechanism. There are two parts to the mechanism. | |||
1. You must supply an implementation of `com.iciql.DbUpgrader` to your `com.iciql.Db` instance. | |||
2. One or more of your table model classes must set the *version* field of the `com.iciql.IQTable` annotation<br> | |||
2. One or more of your table model classes must specify the `IQVersion(version)` annotation<br> | |||
AND/OR<br/> | |||
Your `com.iciql.DbUpgrader` implementation must set the *version* field of the `com.iciql.IQDatabase` annotation | |||
Your `com.iciql.DbUpgrader` implementation must specify the `IQVersion(version)` annotation | |||
### 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: |
@@ -3,6 +3,21 @@ | |||
### 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%)) *released %BUILDDATE%* | |||
- api change release (API v2) | |||
- annotations overhaul to reduce verbosity | |||
- @IQSchema(name="public") -> @IQSchema("public") | |||
- @IQDatabase(version=2) -> @IQVersion(2) | |||
- @IQTable(version=2) -> @IQVersion(2) | |||
- @IQIndex annotation simplified to be used for one index definition and expanded to specify index name | |||
- added @IQIndexes annotation to specify multiple IQIndex annotations<br/> | |||
%BEGINCODE% | |||
@IQIndexes({ @IQIndex("name"), @IQIndex(name="myindexname" value={"name", "nickname"}) }) | |||
%ENDCODE% | |||
### 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)) *released 2011-08-03* | |||
- initial release (API v1) | |||
*API changes compared to JaQu from H2 1.3.157 sources* | |||
@@ -32,8 +47,4 @@ | |||
- QueryConditon.bigger => QueryCondition.exceeds | |||
- QueryConditon.biggerEqual => QueryCondition.atLeast | |||
- QueryConditon.smaller => QueryCondition.lessThan | |||
- QueryConditon.smallEqual => QueryCondition.atMost | |||
### Older Releases | |||
none | |||
- QueryConditon.smallEqual => QueryCondition.atMost |
@@ -34,7 +34,7 @@ import java.util.Set; | |||
import javax.sql.DataSource; | |||
import com.iciql.DbUpgrader.DefaultDbUpgrader; | |||
import com.iciql.Iciql.IQDatabase; | |||
import com.iciql.Iciql.IQVersion; | |||
import com.iciql.Iciql.IQTable; | |||
import com.iciql.SQLDialect.DefaultSQLDialect; | |||
import com.iciql.SQLDialect.H2Dialect; | |||
@@ -230,8 +230,8 @@ public class Db { | |||
// flag as checked immediately because calls are nested. | |||
upgradeChecked.add(dbUpgrader.getClass()); | |||
IQDatabase model = dbUpgrader.getClass().getAnnotation(IQDatabase.class); | |||
if (model.version() > 0) { | |||
IQVersion model = dbUpgrader.getClass().getAnnotation(IQVersion.class); | |||
if (model.value() > 0) { | |||
DbVersion v = new DbVersion(); | |||
DbVersion dbVersion = | |||
// (SCHEMA="" && TABLE="") == DATABASE | |||
@@ -239,17 +239,17 @@ public class Db { | |||
if (dbVersion == null) { | |||
// database has no version registration, but model specifies | |||
// version: insert DbVersion entry and return. | |||
DbVersion newDb = new DbVersion(model.version()); | |||
DbVersion newDb = new DbVersion(model.value()); | |||
insert(newDb); | |||
} else { | |||
// database has a version registration: | |||
// check to see if upgrade is required. | |||
if ((model.version() > dbVersion.version) && (dbUpgrader != null)) { | |||
if ((model.value() > dbVersion.version) && (dbUpgrader != null)) { | |||
// database is an older version than the model | |||
boolean success = dbUpgrader | |||
.upgradeDatabase(this, dbVersion.version, model.version()); | |||
.upgradeDatabase(this, dbVersion.version, model.value()); | |||
if (success) { | |||
dbVersion.version = model.version(); | |||
dbVersion.version = model.value(); | |||
update(dbVersion); | |||
} | |||
} | |||
@@ -316,8 +316,8 @@ public class Db { | |||
} | |||
public synchronized void setDbUpgrader(DbUpgrader upgrader) { | |||
if (!upgrader.getClass().isAnnotationPresent(IQDatabase.class)) { | |||
throw new IciqlException("DbUpgrader must be annotated with " + IQDatabase.class.getSimpleName()); | |||
if (!upgrader.getClass().isAnnotationPresent(IQVersion.class)) { | |||
throw new IciqlException("DbUpgrader must be annotated with " + IQVersion.class.getSimpleName()); | |||
} | |||
this.dbUpgrader = upgrader; | |||
upgradeChecked.clear(); |
@@ -17,7 +17,7 @@ | |||
package com.iciql; | |||
import com.iciql.Iciql.IQDatabase; | |||
import com.iciql.Iciql.IQVersion; | |||
/** | |||
* Interface which defines a class to handle table changes based on model | |||
@@ -65,7 +65,7 @@ public interface DbUpgrader { | |||
* The default database upgrader. It throws runtime exception instead of | |||
* handling upgrade requests. | |||
*/ | |||
@IQDatabase(version = 0) | |||
@IQVersion(0) | |||
public static class DefaultDbUpgrader implements DbUpgrader { | |||
public boolean upgradeDatabase(Db db, int fromVersion, int toVersion) { |
@@ -140,11 +140,13 @@ import java.lang.annotation.Target; | |||
public interface Iciql { | |||
/** | |||
* An annotation for a database. | |||
* An annotation for an iciql version. | |||
* <p> | |||
* @IQVersion(1) | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface IQDatabase { | |||
public @interface IQVersion { | |||
/** | |||
* If set to a non-zero value, iciql maintains a "_iq_versions" table | |||
@@ -153,12 +155,14 @@ public interface Iciql { | |||
* statements. Default: 0. You must specify a DbUpgrader on your Db | |||
* object to use this parameter. | |||
*/ | |||
int version() default 0; | |||
int value() default 0; | |||
} | |||
/** | |||
* An annotation for a schema. | |||
* <p> | |||
* @IQSchema("PUBLIC") | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
@@ -167,7 +171,7 @@ public interface Iciql { | |||
/** | |||
* The schema may be optionally specified. Default: unspecified. | |||
*/ | |||
String name() default ""; | |||
String value() default ""; | |||
} | |||
@@ -180,58 +184,54 @@ public interface Iciql { | |||
/** | |||
* An index annotation. | |||
* <p> | |||
* <ul> | |||
* <li>@IQIndex("name") | |||
* <li>@IQIndex({"street", "city"}) | |||
* <li>@IQIndex(name="streetidx", value={"street", "city"}) | |||
* <li>@IQIndex(name="addressidx", type=IndexType.UNIQUE, value={"house_number", "street", "city"}) | |||
* </ul> | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface IQIndex { | |||
/** | |||
* Standard indexes may be optionally specified. | |||
* <ul> | |||
* <li>standard = "id, name"</li> | |||
* <li>standard = "id name"</li> | |||
* <li>standard = { "id name", "date" }</li> | |||
* </ul> | |||
* Standard indexes may still be added in the define() method if the | |||
* model class is not annotated with IQTable. Default: unspecified. | |||
* Index name. If null or empty, iciql will generate one. | |||
*/ | |||
String[] standard() default {}; | |||
String name() default ""; | |||
/** | |||
* Unique indexes may be optionally specified. | |||
* Type of the index. | |||
* <ul> | |||
* <li>unique = "id, name"</li> | |||
* <li>unique = "id name"</li> | |||
* <li>unique = { "id name", "date" }</li> | |||
* <li>com.iciql.iciql.IndexType.STANDARD | |||
* <li>com.iciql.iciql.IndexType.UNIQUE | |||
* <li>com.iciql.iciql.IndexType.HASH | |||
* <li>com.iciql.iciql.IndexType.UNIQUE_HASH | |||
* </ul> | |||
* Unique indexes may still be added in the define() method if the model | |||
* class is not annotated with IQTable. Default: unspecified. | |||
* | |||
* HASH indexes may only be valid for single column indexes. | |||
* | |||
*/ | |||
String[] unique() default {}; | |||
IndexType type() default IndexType.STANDARD; | |||
/** | |||
* Hash indexes may be optionally specified. | |||
* Columns to include in index. | |||
* <ul> | |||
* <li>hash = "name" | |||
* <li>hash = { "name", "date" } | |||
* <li>single column index: value = "id" | |||
* <li>multiple column index: value = { "id", "name", "date" } | |||
* </ul> | |||
* Hash indexes may still be added in the define() method if the model | |||
* class is not annotated with IQTable. Default: unspecified. | |||
*/ | |||
String[] hash() default {}; | |||
/** | |||
* Unique hash indexes may be optionally specified. | |||
* <ul> | |||
* <li>uniqueHash = "id" | |||
* <li>uniqueHash = "name" | |||
* <li>uniqueHash = { "id", "name" } | |||
* </ul> | |||
* Unique hash indexes may still be added in the define() method if the | |||
* model class is not annotated with IQTable. Default: unspecified. | |||
*/ | |||
String[] uniqueHash() default {}; | |||
String[] value() default {}; | |||
} | |||
/** | |||
* Annotation to specify multiple indexes. | |||
*/ | |||
@Retention(RetentionPolicy.RUNTIME) | |||
@Target(ElementType.TYPE) | |||
public @interface IQIndexes { | |||
IQIndex[] value() default {}; | |||
} | |||
/** | |||
@@ -295,15 +295,6 @@ public interface Iciql { | |||
* databases. Default: false. | |||
*/ | |||
boolean memoryTable() default false; | |||
/** | |||
* If non-zero, iciql will maintain a "_iq_versions" table within your | |||
* database. The version number is used to call to a registered | |||
* DbUpgrader implementation to perform relevant ALTER statements. | |||
* Default: 0. You must specify a DbUpgrader on your Db object to use | |||
* this parameter. | |||
*/ | |||
int version() default 0; | |||
} | |||
/** |
@@ -27,11 +27,13 @@ import java.util.IdentityHashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import com.iciql.Iciql.IndexType; | |||
import com.iciql.Iciql.IQColumn; | |||
import com.iciql.Iciql.IQIndex; | |||
import com.iciql.Iciql.IQIndexes; | |||
import com.iciql.Iciql.IQSchema; | |||
import com.iciql.Iciql.IQTable; | |||
import com.iciql.Iciql.IQVersion; | |||
import com.iciql.Iciql.IndexType; | |||
import com.iciql.util.StatementBuilder; | |||
import com.iciql.util.StatementLogger; | |||
import com.iciql.util.StringUtils; | |||
@@ -133,9 +135,9 @@ class TableDefinition<T> { | |||
List<FieldDefinition> getFields() { | |||
return fields; | |||
} | |||
FieldDefinition getField(String name) { | |||
for (FieldDefinition field:fields) { | |||
for (FieldDefinition field : fields) { | |||
if (field.columnName.equalsIgnoreCase(name)) { | |||
return field; | |||
} | |||
@@ -199,7 +201,7 @@ class TableDefinition<T> { | |||
*/ | |||
void addIndex(IndexType type, Object[] modelFields) { | |||
List<String> columnNames = mapColumnNames(modelFields); | |||
addIndex(type, columnNames); | |||
addIndex(null, type, columnNames); | |||
} | |||
/** | |||
@@ -210,9 +212,13 @@ class TableDefinition<T> { | |||
* @param columnNames | |||
* the ordered list of column names | |||
*/ | |||
void addIndex(IndexType type, List<String> columnNames) { | |||
void addIndex(String name, IndexType type, List<String> columnNames) { | |||
IndexDefinition index = new IndexDefinition(); | |||
index.indexName = tableName + "_" + indexes.size(); | |||
if (StringUtils.isNullOrEmpty(name)) { | |||
index.indexName = tableName + "_" + indexes.size(); | |||
} else { | |||
index.indexName = name; | |||
} | |||
index.columnNames = Utils.newArrayList(columnNames); | |||
index.type = type; | |||
indexes.add(index); | |||
@@ -376,7 +382,7 @@ class TableDefinition<T> { | |||
} | |||
buff.append(')'); | |||
stat.setSQL(buff.toString()); | |||
StatementLogger.merge(stat.getSQL()); | |||
stat.executeUpdate(); | |||
} | |||
@@ -524,10 +530,10 @@ class TableDefinition<T> { | |||
} | |||
/** | |||
* Retrieve list of columns from index definition. | |||
* Retrieve list of columns from primary key definition. | |||
* | |||
* @param index | |||
* the index columns, separated by space | |||
* the primary key columns, separated by space | |||
* @return the column list | |||
*/ | |||
private List<String> getColumns(String index) { | |||
@@ -554,8 +560,8 @@ class TableDefinition<T> { | |||
if (clazz.isAnnotationPresent(IQSchema.class)) { | |||
IQSchema schemaAnnotation = clazz.getAnnotation(IQSchema.class); | |||
// setup schema name mapping, if properly annotated | |||
if (!StringUtils.isNullOrEmpty(schemaAnnotation.name())) { | |||
schemaName = schemaAnnotation.name(); | |||
if (!StringUtils.isNullOrEmpty(schemaAnnotation.value())) { | |||
schemaName = schemaAnnotation.value(); | |||
} | |||
} | |||
@@ -571,8 +577,11 @@ class TableDefinition<T> { | |||
createTableIfRequired = tableAnnotation.createIfRequired(); | |||
// model version | |||
if (tableAnnotation.version() > 0) { | |||
tableVersion = tableAnnotation.version(); | |||
if (clazz.isAnnotationPresent(IQVersion.class)) { | |||
IQVersion versionAnnotation = clazz.getAnnotation(IQVersion.class); | |||
if (versionAnnotation.value() > 0) { | |||
tableVersion = versionAnnotation.value(); | |||
} | |||
} | |||
// setup the primary index, if properly annotated | |||
@@ -583,34 +592,27 @@ class TableDefinition<T> { | |||
} | |||
if (clazz.isAnnotationPresent(IQIndex.class)) { | |||
IQIndex indexAnnotation = clazz.getAnnotation(IQIndex.class); | |||
// setup the indexes, if properly annotated | |||
addIndexes(IndexType.STANDARD, indexAnnotation.standard()); | |||
addIndexes(IndexType.UNIQUE, indexAnnotation.unique()); | |||
addIndexes(IndexType.HASH, indexAnnotation.hash()); | |||
addIndexes(IndexType.UNIQUE_HASH, indexAnnotation.uniqueHash()); | |||
// single table index | |||
IQIndex index = clazz.getAnnotation(IQIndex.class); | |||
addIndex(index); | |||
} | |||
} | |||
void addIndexes(IndexType type, String[] indexes) { | |||
for (String index : indexes) { | |||
List<String> validatedColumns = getColumns(index); | |||
if (validatedColumns == null) { | |||
return; | |||
if (clazz.isAnnotationPresent(IQIndexes.class)) { | |||
// multiple table indexes | |||
IQIndexes indexes = clazz.getAnnotation(IQIndexes.class); | |||
for (IQIndex index : indexes.value()) { | |||
addIndex(index); | |||
} | |||
addIndex(type, validatedColumns); | |||
} | |||
} | |||
List<IndexDefinition> getIndexes(IndexType type) { | |||
List<IndexDefinition> list = Utils.newArrayList(); | |||
for (IndexDefinition def : indexes) { | |||
if (def.type.equals(type)) { | |||
list.add(def); | |||
} | |||
} | |||
return list; | |||
void addIndex(IQIndex index) { | |||
List<String> columns = Arrays.asList(index.value()); | |||
addIndex(index.name(), index.type(), columns); | |||
} | |||
List<IndexDefinition> getIndexes() { | |||
return indexes; | |||
} | |||
void initObject(Object obj, Map<Object, FieldDefinition> map) { |
@@ -23,6 +23,7 @@ import static com.iciql.ValidationRemark.warn; | |||
import static com.iciql.util.JdbcUtils.closeSilently; | |||
import static com.iciql.util.StringUtils.isNullOrEmpty; | |||
import static java.text.MessageFormat.format; | |||
import java.lang.reflect.Modifier; | |||
import java.sql.DatabaseMetaData; | |||
import java.sql.ResultSet; | |||
@@ -34,14 +35,16 @@ import java.util.List; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.iciql.Iciql.IndexType; | |||
import com.iciql.Iciql.IQColumn; | |||
import com.iciql.Iciql.IQIndex; | |||
import com.iciql.Iciql.IQIndexes; | |||
import com.iciql.Iciql.IQSchema; | |||
import com.iciql.Iciql.IQTable; | |||
import com.iciql.Iciql.IndexType; | |||
import com.iciql.TableDefinition.FieldDefinition; | |||
import com.iciql.TableDefinition.IndexDefinition; | |||
import com.iciql.util.StatementBuilder; | |||
import com.iciql.util.StringUtils; | |||
import com.iciql.util.Utils; | |||
/** | |||
@@ -175,8 +178,10 @@ public class TableInspector { | |||
Set<String> imports = Utils.newHashSet(); | |||
imports.add(IQSchema.class.getCanonicalName()); | |||
imports.add(IQTable.class.getCanonicalName()); | |||
imports.add(IQIndexes.class.getCanonicalName()); | |||
imports.add(IQIndex.class.getCanonicalName()); | |||
imports.add(IQColumn.class.getCanonicalName()); | |||
imports.add(IQColumn.class.getCanonicalName()); | |||
imports.add(IndexType.class.getCanonicalName()); | |||
// fields | |||
StringBuilder fields = new StringBuilder(); | |||
@@ -207,7 +212,7 @@ public class TableInspector { | |||
model.append('@').append(IQSchema.class.getSimpleName()); | |||
model.append('('); | |||
AnnotationBuilder ap = new AnnotationBuilder(); | |||
ap.addParameter("name", schema); | |||
ap.addParameter(null, schema); | |||
model.append(ap); | |||
model.append(')').append(eol); | |||
} | |||
@@ -233,17 +238,11 @@ public class TableInspector { | |||
model.append(ap); | |||
model.append(')').append(eol); | |||
// @IQIndexes | |||
// @IQIndex | |||
ap = new AnnotationBuilder(); | |||
generateIndexAnnotations(ap, "standard", IndexType.STANDARD); | |||
generateIndexAnnotations(ap, "unique", IndexType.UNIQUE); | |||
generateIndexAnnotations(ap, "hash", IndexType.HASH); | |||
generateIndexAnnotations(ap, "uniqueHash", IndexType.UNIQUE_HASH); | |||
if (ap.length() > 0) { | |||
model.append('@').append(IQIndex.class.getSimpleName()); | |||
model.append('('); | |||
model.append(ap); | |||
model.append(')').append(eol); | |||
String indexAnnotations = generateIndexAnnotations(); | |||
if (!StringUtils.isNullOrEmpty(indexAnnotations)) { | |||
model.append(indexAnnotations); | |||
} | |||
// class declaration | |||
@@ -269,32 +268,50 @@ public class TableInspector { | |||
* | |||
* @param ap | |||
*/ | |||
void generateIndexAnnotations(AnnotationBuilder ap, String parameter, IndexType type) { | |||
List<IndexInspector> list = getIndexes(type); | |||
if (list.size() == 0) { | |||
String generateIndexAnnotations() { | |||
if (indexes == null || indexes.size() == 0) { | |||
// no matching indexes | |||
return; | |||
return null; | |||
} | |||
if (list.size() == 1) { | |||
ap.addParameter(parameter, list.get(0).getColumnsString()); | |||
AnnotationBuilder ap = new AnnotationBuilder(); | |||
if (indexes.size() == 1) { | |||
// single index | |||
ap.append(generateIndexAnnotation(indexes.get(0))); | |||
ap.append(eol); | |||
} else { | |||
List<String> parameters = Utils.newArrayList(); | |||
for (IndexInspector index : list) { | |||
parameters.add(index.getColumnsString()); | |||
// multiple indexes | |||
ap.append('@').append(IQIndexes.class.getSimpleName()); | |||
ap.append("({"); | |||
ap.resetCount(); | |||
for (IndexInspector index : indexes.values()) { | |||
ap.appendExceptFirst(", "); | |||
ap.append(generateIndexAnnotation(index)); | |||
} | |||
ap.addParameter(parameter, parameters); | |||
ap.append("})").append(eol); | |||
} | |||
return ap.toString(); | |||
} | |||
private List<IndexInspector> getIndexes(IndexType type) { | |||
List<IndexInspector> list = Utils.newArrayList(); | |||
for (IndexInspector index : indexes.values()) { | |||
if (index.type.equals(type)) { | |||
list.add(index); | |||
} | |||
private String generateIndexAnnotation(IndexInspector index) { | |||
AnnotationBuilder ap = new AnnotationBuilder(); | |||
ap.append('@').append(IQIndex.class.getSimpleName()); | |||
ap.append('('); | |||
ap.resetCount(); | |||
if (!StringUtils.isNullOrEmpty(index.name)) { | |||
ap.addParameter("name", index.name); | |||
} | |||
if (!index.type.equals(IndexType.STANDARD)) { | |||
ap.addParameter("type", IndexType.class.getSimpleName() + "." + index.type.name()); | |||
} | |||
if (ap.getCount() > 0) { | |||
// multiple fields specified | |||
ap.addParameter("values", index.columns); | |||
} else { | |||
// default value | |||
ap.addParameter(null, index.columns); | |||
} | |||
return list; | |||
ap.append(')'); | |||
return ap.toString(); | |||
} | |||
private StatementBuilder generateColumn(Set<String> imports, ColumnInspector col, boolean trimStrings) { | |||
@@ -424,11 +441,10 @@ public class TableInspector { | |||
*/ | |||
private <T> void validate(List<ValidationRemark> remarks, TableDefinition<T> def, IndexInspector index, | |||
boolean throwError) { | |||
List<IndexDefinition> defIndexes = def.getIndexes(IndexType.STANDARD); | |||
List<IndexInspector> dbIndexes = getIndexes(IndexType.STANDARD); | |||
if (defIndexes.size() > dbIndexes.size()) { | |||
List<IndexDefinition> defIndexes = def.getIndexes(); | |||
if (defIndexes.size() > indexes.size()) { | |||
remarks.add(warn(table, IndexType.STANDARD.name(), "More model indexes than database indexes")); | |||
} else if (defIndexes.size() < dbIndexes.size()) { | |||
} else if (defIndexes.size() < indexes.size()) { | |||
remarks.add(warn(table, IndexType.STANDARD.name(), "Model class is missing indexes")); | |||
} | |||
// TODO complete index validation. | |||
@@ -583,15 +599,6 @@ public class TableInspector { | |||
public void addColumn(ResultSet rs) throws SQLException { | |||
columns.add(rs.getString("COLUMN_NAME")); | |||
} | |||
public String getColumnsString() { | |||
StatementBuilder sb = new StatementBuilder(); | |||
for (String col : columns) { | |||
sb.appendExceptFirst(", "); | |||
sb.append(col); | |||
} | |||
return sb.toString().trim(); | |||
} | |||
} | |||
/** | |||
@@ -629,19 +636,23 @@ public class TableInspector { | |||
* parameter list. | |||
*/ | |||
private static class AnnotationBuilder extends StatementBuilder { | |||
AnnotationBuilder() { | |||
super(); | |||
} | |||
void addParameter(String parameter) { | |||
appendExceptFirst(", "); | |||
append(parameter); | |||
} | |||
<T> void addParameter(String parameter, T value) { | |||
appendExceptFirst(", "); | |||
append(parameter); | |||
append('='); | |||
if (!StringUtils.isNullOrEmpty(parameter)) { | |||
append(parameter); | |||
append('='); | |||
} | |||
if (value instanceof List) { | |||
append("{ "); | |||
List<?> list = (List<?>) value; | |||
@@ -663,7 +674,7 @@ public class TableInspector { | |||
if (value instanceof String) { | |||
append('\"'); | |||
} | |||
// TODO escape | |||
// TODO escape | |||
append(value.toString().trim()); | |||
if (value instanceof String) { | |||
append('\"'); |
@@ -99,6 +99,14 @@ public class StatementBuilder { | |||
builder.append(x); | |||
return this; | |||
} | |||
/** | |||
* Returns the current value of the loop counter. | |||
* @return the loop counter | |||
*/ | |||
public int getCount() { | |||
return index; | |||
} | |||
/** | |||
* Reset the loop counter. |
@@ -69,15 +69,18 @@ public class AnnotationsTest { | |||
public void testIndexCreation() throws SQLException { | |||
// test indexes are created, and columns are in the right order | |||
DatabaseMetaData meta = db.getConnection().getMetaData(); | |||
ResultSet rs = meta.getIndexInfo(null, "PUBLIC", "ANNOTATED" + "PRODUCT", false, true); | |||
ResultSet rs = meta.getIndexInfo(null, "PUBLIC", "ANNOTATEDPRODUCT", false, true); | |||
assertTrue(rs.next()); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "PRIMARY_KEY"); | |||
assertTrue(rs.next()); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATED" + "PRODUCT_"); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATEDPRODUCT_0"); | |||
assertStartsWith(rs.getString("COLUMN_NAME"), "NAME"); | |||
assertTrue(rs.next()); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATED" + "PRODUCT_"); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "ANNOTATEDPRODUCT_0"); | |||
assertStartsWith(rs.getString("COLUMN_NAME"), "CAT"); | |||
assertTrue(rs.next()); | |||
assertStartsWith(rs.getString("INDEX_NAME"), "NAMEIDX"); | |||
assertStartsWith(rs.getString("COLUMN_NAME"), "NAME"); | |||
assertFalse(rs.next()); | |||
} | |||
@@ -34,7 +34,7 @@ import com.iciql.Db; | |||
import com.iciql.DbInspector; | |||
import com.iciql.DbUpgrader; | |||
import com.iciql.DbVersion; | |||
import com.iciql.Iciql.IQDatabase; | |||
import com.iciql.Iciql.IQVersion; | |||
import com.iciql.ValidationRemark; | |||
import com.iciql.test.models.Product; | |||
import com.iciql.test.models.ProductAnnotationOnly; | |||
@@ -115,7 +115,7 @@ public class ModelsTest { | |||
true); | |||
assertEquals(1, models.size()); | |||
// a poor test, but a start | |||
assertEquals(1361, models.get(0).length()); | |||
assertEquals(1564, models.get(0).length()); | |||
} | |||
@Test | |||
@@ -157,7 +157,7 @@ public class ModelsTest { | |||
/** | |||
* A sample database upgrader class. | |||
*/ | |||
@IQDatabase(version = 2) | |||
@IQVersion(2) | |||
class TestDbUpgrader implements DbUpgrader { | |||
final AtomicInteger oldVersion = new AtomicInteger(0); | |||
final AtomicInteger newVersion = new AtomicInteger(0); |
@@ -22,14 +22,17 @@ import java.util.List; | |||
import com.iciql.Iciql.IQColumn; | |||
import com.iciql.Iciql.IQIndex; | |||
import com.iciql.Iciql.IQIndexes; | |||
import com.iciql.Iciql.IQTable; | |||
import com.iciql.Iciql.IndexType; | |||
/** | |||
* A table containing product data. | |||
*/ | |||
@IQTable(name = "AnnotatedProduct", primaryKey = "id") | |||
@IQIndex(standard = "name, cat") | |||
@IQIndexes({ @IQIndex({ "name", "cat" }), | |||
@IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") }) | |||
public class ProductAnnotationOnly { | |||
@IQColumn(autoIncrement = true) | |||
@@ -67,9 +70,10 @@ public class ProductAnnotationOnly { | |||
this.unmappedField = unmappedField; | |||
} | |||
private static ProductAnnotationOnly create(int productId, String productName, String category, double unitPrice, | |||
int unitsInStock, String unmappedField) { | |||
return new ProductAnnotationOnly(productId, productName, category, unitPrice, unitsInStock, unmappedField); | |||
private static ProductAnnotationOnly create(int productId, String productName, String category, | |||
double unitPrice, int unitsInStock, String unmappedField) { | |||
return new ProductAnnotationOnly(productId, productName, category, unitPrice, unitsInStock, | |||
unmappedField); | |||
} | |||
public static List<ProductAnnotationOnly> getList() { |
@@ -29,7 +29,7 @@ import com.iciql.Iciql.IQTable; | |||
*/ | |||
@IQTable(annotationsOnly = false) | |||
@IQIndex(standard = "name, cat") | |||
@IQIndex({"name", "cat" }) | |||
public class ProductMixedAnnotation { | |||
public Double unitPrice; |
@@ -22,13 +22,19 @@ import java.util.List; | |||
import java.util.Random; | |||
import com.iciql.Iciql.IQColumn; | |||
import com.iciql.Iciql.IQIndex; | |||
import com.iciql.Iciql.IQIndexes; | |||
import com.iciql.Iciql.IQTable; | |||
import com.iciql.Iciql.IQVersion; | |||
import com.iciql.Iciql.IndexType; | |||
import com.iciql.util.Utils; | |||
/** | |||
* A data class that contains a column for each data type. | |||
*/ | |||
@IQTable(strictTypeMapping = true, version = 1) | |||
@IQTable(strictTypeMapping = true) | |||
@IQIndexes({ @IQIndex({ "myLong", "myInteger" }), @IQIndex(type = IndexType.HASH, value = "myString") }) | |||
@IQVersion(1) | |||
public class SupportedTypes { | |||
public static final SupportedTypes SAMPLE = new SupportedTypes(); | |||
@@ -123,7 +129,8 @@ public class SupportedTypes { | |||
/** | |||
* This class demonstrates the table upgrade. | |||
*/ | |||
@IQTable(name = "SupportedTypes", version = 2, inheritColumns = true, strictTypeMapping = true) | |||
@IQTable(name = "SupportedTypes", inheritColumns = true, strictTypeMapping = true) | |||
@IQVersion(2) | |||
public static class SupportedTypes2 extends SupportedTypes { | |||
public SupportedTypes2() { |