]> source.dussan.org Git - iciql.git/commitdiff
Overhauling annotations.
authorJames Moger <james.moger@gmail.com>
Thu, 4 Aug 2011 18:10:59 +0000 (14:10 -0400)
committerJames Moger <james.moger@gmail.com>
Thu, 4 Aug 2011 18:10:59 +0000 (14:10 -0400)
* @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

14 files changed:
docs/01_model_classes.mkd
docs/02_table_versioning.mkd
docs/05_releases.mkd
src/com/iciql/Db.java
src/com/iciql/DbUpgrader.java
src/com/iciql/Iciql.java
src/com/iciql/TableDefinition.java
src/com/iciql/TableInspector.java
src/com/iciql/util/StatementBuilder.java
tests/com/iciql/test/AnnotationsTest.java
tests/com/iciql/test/ModelsTest.java
tests/com/iciql/test/models/ProductAnnotationOnly.java
tests/com/iciql/test/models/ProductMixedAnnotation.java
tests/com/iciql/test/models/SupportedTypes.java

index 3ca7630cbca099b59232debfbca2d5fc87a52131..a0db6a1d1ca03d1ec4321a31905d99a4a3d29b1b 100644 (file)
@@ -64,8 +64,7 @@ Please consult the `com.iciql.ModelUtils` class for details.
 2. the model class must have a default public constructor\r
 \r
 ### Configuration Limitations\r
-1. index names can not be specified\r
-2. triggers, views, and other advanced database features are unimplemented\r
+Triggers, views, and other advanced database features are unimplemented.\r
 \r
 ## Annotation Configuration\r
 The recommended approach to setup a model class is to annotate the class and field declarations.\r
@@ -89,7 +88,10 @@ import com.iciql.Iciql.IQIndex;
 import com.iciql.Iciql.IQTable;\r
 \r
 @IQTable\r
-@IQIndex(standard = {"productName", "category"})\r
+@IQIndexes({\r
+  @IQIndex({"productName", "category"}),\r
+  @IQIndex(name="nameindex", value="productName")\r
+})\r
 public class Product {\r
 \r
        @IQColumn(primaryKey = true)\r
index 0c778cb696f5cd0a94b004577eac5fbd2d339a37..4650f74eb2910401387dccaec6336c56fe6e8f03 100644 (file)
@@ -3,9 +3,9 @@
 Iciql supports an optional, simple versioning mechanism.  There are two parts to the mechanism.\r
 \r
 1. You must supply an implementation of `com.iciql.DbUpgrader` to your `com.iciql.Db` instance.\r
-2. One or more of your table model classes must set the *version* field of the `com.iciql.IQTable` annotation<br>\r
+2. One or more of your table model classes must specify the `IQVersion(version)` annotation<br>\r
 AND/OR<br/>\r
-Your `com.iciql.DbUpgrader` implementation must set the *version* field of the `com.iciql.IQDatabase` annotation\r
+Your `com.iciql.DbUpgrader` implementation must specify the `IQVersion(version)` annotation\r
 \r
 ### How does it work?\r
 If you choose to use versioning, iciql will maintain a table within your database named *_iq_versions* which is defined as:\r
index f63a171cb2628c43d2d578ae83df4b35ee9576d9..db29860af9bf5826011ab495fbc536649ade437f 100644 (file)
@@ -3,6 +3,21 @@
 ### Current Release\r
 **%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%*\r
 \r
+- api change release (API v2)\r
+- annotations overhaul to reduce verbosity\r
+    - @IQSchema(name="public") -> @IQSchema("public")\r
+    - @IQDatabase(version=2) -> @IQVersion(2)\r
+    - @IQTable(version=2) -> @IQVersion(2)\r
+    - @IQIndex annotation simplified to be used for one index definition and expanded to specify index name\r
+    - added @IQIndexes annotation to specify multiple IQIndex annotations<br/>\r
+%BEGINCODE%\r
+@IQIndexes({ @IQIndex("name"), @IQIndex(name="myindexname" value={"name", "nickname"}) })\r
+%ENDCODE%\r
+\r
+### Older Releases\r
+\r
+**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*\r
+\r
 - initial release (API v1)\r
 \r
 *API changes compared to JaQu from H2 1.3.157 sources*\r
@@ -32,8 +47,4 @@
     - QueryConditon.bigger =&gt; QueryCondition.exceeds\r
     - QueryConditon.biggerEqual =&gt; QueryCondition.atLeast\r
     - QueryConditon.smaller =&gt; QueryCondition.lessThan\r
-    - QueryConditon.smallEqual =&gt; QueryCondition.atMost\r
-\r
-### Older Releases\r
-\r
-none
\ No newline at end of file
+    - QueryConditon.smallEqual =&gt; QueryCondition.atMost
\ No newline at end of file
index 3f86d15485cd6c0eedfceb38a1b497ce977def04..f70a37e5a660feee1088877fe406454c7d0eef13 100644 (file)
@@ -34,7 +34,7 @@ import java.util.Set;
 import javax.sql.DataSource;\r
 \r
 import com.iciql.DbUpgrader.DefaultDbUpgrader;\r
-import com.iciql.Iciql.IQDatabase;\r
+import com.iciql.Iciql.IQVersion;\r
 import com.iciql.Iciql.IQTable;\r
 import com.iciql.SQLDialect.DefaultSQLDialect;\r
 import com.iciql.SQLDialect.H2Dialect;\r
@@ -230,8 +230,8 @@ public class Db {
                        // flag as checked immediately because calls are nested.\r
                        upgradeChecked.add(dbUpgrader.getClass());\r
 \r
-                       IQDatabase model = dbUpgrader.getClass().getAnnotation(IQDatabase.class);\r
-                       if (model.version() > 0) {\r
+                       IQVersion model = dbUpgrader.getClass().getAnnotation(IQVersion.class);\r
+                       if (model.value() > 0) {\r
                                DbVersion v = new DbVersion();\r
                                DbVersion dbVersion =\r
                                // (SCHEMA="" && TABLE="") == DATABASE\r
@@ -239,17 +239,17 @@ public class Db {
                                if (dbVersion == null) {\r
                                        // database has no version registration, but model specifies\r
                                        // version: insert DbVersion entry and return.\r
-                                       DbVersion newDb = new DbVersion(model.version());\r
+                                       DbVersion newDb = new DbVersion(model.value());\r
                                        insert(newDb);\r
                                } else {\r
                                        // database has a version registration:\r
                                        // check to see if upgrade is required.\r
-                                       if ((model.version() > dbVersion.version) && (dbUpgrader != null)) {\r
+                                       if ((model.value() > dbVersion.version) && (dbUpgrader != null)) {\r
                                                // database is an older version than the model\r
                                                boolean success = dbUpgrader\r
-                                                               .upgradeDatabase(this, dbVersion.version, model.version());\r
+                                                               .upgradeDatabase(this, dbVersion.version, model.value());\r
                                                if (success) {\r
-                                                       dbVersion.version = model.version();\r
+                                                       dbVersion.version = model.value();\r
                                                        update(dbVersion);\r
                                                }\r
                                        }\r
@@ -316,8 +316,8 @@ public class Db {
        }\r
 \r
        public synchronized void setDbUpgrader(DbUpgrader upgrader) {\r
-               if (!upgrader.getClass().isAnnotationPresent(IQDatabase.class)) {\r
-                       throw new IciqlException("DbUpgrader must be annotated with " + IQDatabase.class.getSimpleName());\r
+               if (!upgrader.getClass().isAnnotationPresent(IQVersion.class)) {\r
+                       throw new IciqlException("DbUpgrader must be annotated with " + IQVersion.class.getSimpleName());\r
                }\r
                this.dbUpgrader = upgrader;\r
                upgradeChecked.clear();\r
index c4ab36b24589faf9ce950b6f70e0e962af1a09d7..1303f4e5bc9ce3f4083fa34394d1bb5c9d7e9c89 100644 (file)
@@ -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) {
index 7267d33a901374439317df9ce00001747d3b58f6..35ad8ccccc4080f40ec713223dc39aef3d822910 100644 (file)
@@ -140,11 +140,13 @@ import java.lang.annotation.Target;
 public interface Iciql {\r
 \r
        /**\r
-        * An annotation for a database.\r
+        * An annotation for an iciql version.\r
+        * <p>\r
+        * @IQVersion(1)\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
        @Target(ElementType.TYPE)\r
-       public @interface IQDatabase {\r
+       public @interface IQVersion {\r
 \r
                /**\r
                 * If set to a non-zero value, iciql maintains a "_iq_versions" table\r
@@ -153,12 +155,14 @@ public interface Iciql {
                 * statements. Default: 0. You must specify a DbUpgrader on your Db\r
                 * object to use this parameter.\r
                 */\r
-               int version() default 0;\r
+               int value() default 0;\r
 \r
        }\r
 \r
        /**\r
         * An annotation for a schema.\r
+        * <p>\r
+        * @IQSchema("PUBLIC")\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
        @Target(ElementType.TYPE)\r
@@ -167,7 +171,7 @@ public interface Iciql {
                /**\r
                 * The schema may be optionally specified. Default: unspecified.\r
                 */\r
-               String name() default "";\r
+               String value() default "";\r
 \r
        }\r
 \r
@@ -180,58 +184,54 @@ public interface Iciql {
 \r
        /**\r
         * An index annotation.\r
+        * <p>\r
+        * <ul>\r
+        * <li>@IQIndex("name")\r
+        * <li>@IQIndex({"street", "city"})\r
+        * <li>@IQIndex(name="streetidx", value={"street", "city"})\r
+        * <li>@IQIndex(name="addressidx", type=IndexType.UNIQUE, value={"house_number", "street", "city"})\r
+        * </ul>\r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
        @Target(ElementType.TYPE)\r
        public @interface IQIndex {\r
 \r
                /**\r
-                * Standard indexes may be optionally specified.\r
-                * <ul>\r
-                * <li>standard = "id, name"</li>\r
-                * <li>standard = "id name"</li>\r
-                * <li>standard = { "id name", "date" }</li>\r
-                * </ul>\r
-                * Standard indexes may still be added in the define() method if the\r
-                * model class is not annotated with IQTable. Default: unspecified.\r
+                * Index name. If null or empty, iciql will generate one.\r
                 */\r
-               String[] standard() default {};\r
+               String name() default "";\r
 \r
                /**\r
-                * Unique indexes may be optionally specified.\r
+                * Type of the index.\r
                 * <ul>\r
-                * <li>unique = "id, name"</li>\r
-                * <li>unique = "id name"</li>\r
-                * <li>unique = { "id name", "date" }</li>\r
+                * <li>com.iciql.iciql.IndexType.STANDARD\r
+                * <li>com.iciql.iciql.IndexType.UNIQUE\r
+                * <li>com.iciql.iciql.IndexType.HASH\r
+                * <li>com.iciql.iciql.IndexType.UNIQUE_HASH\r
                 * </ul>\r
-                * Unique indexes may still be added in the define() method if the model\r
-                * class is not annotated with IQTable. Default: unspecified.\r
+                * \r
+                * HASH indexes may only be valid for single column indexes.\r
+                * \r
                 */\r
-               String[] unique() default {};\r
+               IndexType type() default IndexType.STANDARD;\r
 \r
                /**\r
-                * Hash indexes may be optionally specified.\r
+                * Columns to include in index.\r
                 * <ul>\r
-                * <li>hash = "name"\r
-                * <li>hash = { "name", "date" }\r
+                * <li>single column index: value = "id"\r
+                * <li>multiple column index: value = { "id", "name", "date" }\r
                 * </ul>\r
-                * Hash indexes may still be added in the define() method if the model\r
-                * class is not annotated with IQTable. Default: unspecified.\r
                 */\r
-               String[] hash() default {};\r
-\r
-               /**\r
-                * Unique hash indexes may be optionally specified.\r
-                * <ul>\r
-                * <li>uniqueHash = "id"\r
-                * <li>uniqueHash = "name"\r
-                * <li>uniqueHash = { "id", "name" }\r
-                * </ul>\r
-                * Unique hash indexes may still be added in the define() method if the\r
-                * model class is not annotated with IQTable. Default: unspecified.\r
-                */\r
-               String[] uniqueHash() default {};\r
+               String[] value() default {};\r
+       }\r
 \r
+       /**\r
+        * Annotation to specify multiple indexes.\r
+        */\r
+       @Retention(RetentionPolicy.RUNTIME)\r
+       @Target(ElementType.TYPE)\r
+       public @interface IQIndexes {\r
+               IQIndex[] value() default {};\r
        }\r
 \r
        /**\r
@@ -295,15 +295,6 @@ public interface Iciql {
                 * databases. Default: false.\r
                 */\r
                boolean memoryTable() default false;\r
-\r
-               /**\r
-                * If non-zero, iciql will maintain a "_iq_versions" table within your\r
-                * database. The version number is used to call to a registered\r
-                * DbUpgrader implementation to perform relevant ALTER statements.\r
-                * Default: 0. You must specify a DbUpgrader on your Db object to use\r
-                * this parameter.\r
-                */\r
-               int version() default 0;\r
        }\r
 \r
        /**\r
index 883ce33f8a812f37df83cdb69be896c5ce9fc87d..456d0f49f04fb6f275d27e97f506c253cac20f98 100644 (file)
@@ -27,11 +27,13 @@ import java.util.IdentityHashMap;
 import java.util.List;\r
 import java.util.Map;\r
 \r
-import com.iciql.Iciql.IndexType;\r
 import com.iciql.Iciql.IQColumn;\r
 import com.iciql.Iciql.IQIndex;\r
+import com.iciql.Iciql.IQIndexes;\r
 import com.iciql.Iciql.IQSchema;\r
 import com.iciql.Iciql.IQTable;\r
+import com.iciql.Iciql.IQVersion;\r
+import com.iciql.Iciql.IndexType;\r
 import com.iciql.util.StatementBuilder;\r
 import com.iciql.util.StatementLogger;\r
 import com.iciql.util.StringUtils;\r
@@ -133,9 +135,9 @@ class TableDefinition<T> {
        List<FieldDefinition> getFields() {\r
                return fields;\r
        }\r
-       \r
+\r
        FieldDefinition getField(String name) {\r
-               for (FieldDefinition field:fields) {\r
+               for (FieldDefinition field : fields) {\r
                        if (field.columnName.equalsIgnoreCase(name)) {\r
                                return field;\r
                        }\r
@@ -199,7 +201,7 @@ class TableDefinition<T> {
         */\r
        void addIndex(IndexType type, Object[] modelFields) {\r
                List<String> columnNames = mapColumnNames(modelFields);\r
-               addIndex(type, columnNames);\r
+               addIndex(null, type, columnNames);\r
        }\r
 \r
        /**\r
@@ -210,9 +212,13 @@ class TableDefinition<T> {
         * @param columnNames\r
         *            the ordered list of column names\r
         */\r
-       void addIndex(IndexType type, List<String> columnNames) {\r
+       void addIndex(String name, IndexType type, List<String> columnNames) {\r
                IndexDefinition index = new IndexDefinition();\r
-               index.indexName = tableName + "_" + indexes.size();\r
+               if (StringUtils.isNullOrEmpty(name)) {\r
+                       index.indexName = tableName + "_" + indexes.size();\r
+               } else {\r
+                       index.indexName = name;\r
+               }\r
                index.columnNames = Utils.newArrayList(columnNames);\r
                index.type = type;\r
                indexes.add(index);\r
@@ -376,7 +382,7 @@ class TableDefinition<T> {
                }\r
                buff.append(')');\r
                stat.setSQL(buff.toString());\r
-               \r
+\r
                StatementLogger.merge(stat.getSQL());\r
                stat.executeUpdate();\r
        }\r
@@ -524,10 +530,10 @@ class TableDefinition<T> {
        }\r
 \r
        /**\r
-        * Retrieve list of columns from index definition.\r
+        * Retrieve list of columns from primary key definition.\r
         * \r
         * @param index\r
-        *            the index columns, separated by space\r
+        *            the primary key columns, separated by space\r
         * @return the column list\r
         */\r
        private List<String> getColumns(String index) {\r
@@ -554,8 +560,8 @@ class TableDefinition<T> {
                if (clazz.isAnnotationPresent(IQSchema.class)) {\r
                        IQSchema schemaAnnotation = clazz.getAnnotation(IQSchema.class);\r
                        // setup schema name mapping, if properly annotated\r
-                       if (!StringUtils.isNullOrEmpty(schemaAnnotation.name())) {\r
-                               schemaName = schemaAnnotation.name();\r
+                       if (!StringUtils.isNullOrEmpty(schemaAnnotation.value())) {\r
+                               schemaName = schemaAnnotation.value();\r
                        }\r
                }\r
 \r
@@ -571,8 +577,11 @@ class TableDefinition<T> {
                        createTableIfRequired = tableAnnotation.createIfRequired();\r
 \r
                        // model version\r
-                       if (tableAnnotation.version() > 0) {\r
-                               tableVersion = tableAnnotation.version();\r
+                       if (clazz.isAnnotationPresent(IQVersion.class)) {\r
+                               IQVersion versionAnnotation = clazz.getAnnotation(IQVersion.class);\r
+                               if (versionAnnotation.value() > 0) {\r
+                                       tableVersion = versionAnnotation.value();\r
+                               }\r
                        }\r
 \r
                        // setup the primary index, if properly annotated\r
@@ -583,34 +592,27 @@ class TableDefinition<T> {
                }\r
 \r
                if (clazz.isAnnotationPresent(IQIndex.class)) {\r
-                       IQIndex indexAnnotation = clazz.getAnnotation(IQIndex.class);\r
-\r
-                       // setup the indexes, if properly annotated\r
-                       addIndexes(IndexType.STANDARD, indexAnnotation.standard());\r
-                       addIndexes(IndexType.UNIQUE, indexAnnotation.unique());\r
-                       addIndexes(IndexType.HASH, indexAnnotation.hash());\r
-                       addIndexes(IndexType.UNIQUE_HASH, indexAnnotation.uniqueHash());\r
+                       // single table index\r
+                       IQIndex index = clazz.getAnnotation(IQIndex.class);\r
+                       addIndex(index);\r
                }\r
-       }\r
 \r
-       void addIndexes(IndexType type, String[] indexes) {\r
-               for (String index : indexes) {\r
-                       List<String> validatedColumns = getColumns(index);\r
-                       if (validatedColumns == null) {\r
-                               return;\r
+               if (clazz.isAnnotationPresent(IQIndexes.class)) {\r
+                       // multiple table indexes\r
+                       IQIndexes indexes = clazz.getAnnotation(IQIndexes.class);\r
+                       for (IQIndex index : indexes.value()) {\r
+                               addIndex(index);\r
                        }\r
-                       addIndex(type, validatedColumns);\r
                }\r
        }\r
 \r
-       List<IndexDefinition> getIndexes(IndexType type) {\r
-               List<IndexDefinition> list = Utils.newArrayList();\r
-               for (IndexDefinition def : indexes) {\r
-                       if (def.type.equals(type)) {\r
-                               list.add(def);\r
-                       }\r
-               }\r
-               return list;\r
+       void addIndex(IQIndex index) {\r
+               List<String> columns = Arrays.asList(index.value());\r
+               addIndex(index.name(), index.type(), columns);\r
+       }\r
+\r
+       List<IndexDefinition> getIndexes() {\r
+               return indexes;\r
        }\r
 \r
        void initObject(Object obj, Map<Object, FieldDefinition> map) {\r
index f920315bb0864ebe9f0a9694c353621c6d59c81e..8e537b4addd2ad09fc513aa822765057dc5952d0 100644 (file)
@@ -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('\"');
index c2974ae1326520334906763a18a7b3269462ad1f..65c06793eb28d28bccd92ddf3d46630462a16884 100644 (file)
@@ -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.
index 367e6e1c594f57b02fba21c4fc41961993bd01a9..92e0d5e30a85c2b38bfa14313aa021bd71395218 100644 (file)
@@ -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());
        }
 
index b3974b80c16dc19e259384ac1c7916f4ac381435..851da92da5a061413f842bd4ae0cdbd1318c1efc 100644 (file)
@@ -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);
index 79212377f672ed5a87a18892055b1ca29fa4169d..6b8d42014120e39bb14ad6ad4965dba15a76a0f1 100644 (file)
@@ -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() {
index f90bd65331af8b5c347f5ac3d1221ef96364970c..1d3cb8fbd126ec5a00926ad9c2f3799fed224cb0 100644 (file)
@@ -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;
index 26692fc99b7898069145197ef86d36744b4f8075..66c25d49cc379bb9bcb42f870d4a2b4384d7538d 100644 (file)
@@ -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() {