]> source.dussan.org Git - iciql.git/commitdiff
Full primitives support.
authorJames Moger <james.moger@gmail.com>
Fri, 12 Aug 2011 17:04:29 +0000 (13:04 -0400)
committerJames Moger <james.moger@gmail.com>
Fri, 12 Aug 2011 17:04:29 +0000 (13:04 -0400)
NOTICE
docs/01_model_classes.mkd
docs/05_releases.mkd
src/com/iciql/Query.java
src/com/iciql/QueryWhere.java
src/com/iciql/TableDefinition.java
src/com/iciql/util/Utils.java
tests/com/iciql/test/AliasMapTest.java
tests/com/iciql/test/PrimitivesTest.java
tests/com/iciql/test/models/PrimitivesModel.java

diff --git a/NOTICE b/NOTICE
index 8b6516c50a0d034ddf4c1494130130af2bd8a28a..76b6a69e44f3d3abc6a2e9b9e5d2a4cd0f95b538 100644 (file)
--- a/NOTICE
+++ b/NOTICE
@@ -36,6 +36,14 @@ H2 Database
    Eclipse Public License, Version 1.0.\r
    \r
    http://code.google.com/p/h2database\r
+   \r
+---------------------------------------------------------------------------\r
+HSQL Database\r
+---------------------------------------------------------------------------\r
+   hsqldb, released under the\r
+   BSD.\r
+   \r
+   http://hsqldb.org   \r
 \r
 ---------------------------------------------------------------------------\r
 MarkdownPapers\r
index cd52c2bf7643eb085b300ebff62be061272b4f5f..1b370d8594a824806fdae59867ddebb17ac33e4f 100644 (file)
@@ -8,64 +8,74 @@ Alternatively, model classes can be automatically generated by iciql using the m
 ### Configuration Requirements and Limitations\r
 \r
 1. Your model class **must** provide a public default constructor.\r
-2. All columns are assumed NULLABLE unless explicitly set *@IQColumn(nullable = false)*. \r
-3. Only the specified types are supported.  Other types such as arrays and custom types are not supported.\r
-4. Triggers, views, and other advanced database features are not supported.\r
+2. All **Object** columns are assumed NULLABLE unless explicitly set *@IQColumn(nullable = false)*.\r
+3. All **Primitive** columns are assumed NOT NULLABLE unless explicitly set *@IQColumn(nullable = true)*.\r
+4. Only the specified types are supported.  Any other types are not supported.\r
+5. Triggers, views, and other advanced database features are not supported.\r
 \r
-### Fully Supported Data Types\r
-The following data types can be used for all iciql expressions.\r
+### Supported Data Types\r
 <table>\r
-<tr><th colspan="2">Standard SQL Types</th></tr>\r
-<tr><td>java.lang.String</td>\r
+<tr><td colspan="3"><b>Fully Supported Types</b><br/>\r
+can be used for all iciql expressions\r
+</tr>\r
+<tr><th>Object</th><th>Primitive</th><th>SQL Type</th></tr>\r
+<tr><td>java.lang.String</td><td></td>\r
 <td>VARCHAR *(length > 0)* or CLOB *(length == 0)*</td></tr>\r
        \r
-<tr><td>java.lang.Boolean</td>\r
-<td>BIT</td></tr>\r
+<tr><td>java.lang.Boolean</td><td>boolean</td>\r
+<td>BOOLEAN</td></tr>\r
        \r
-<tr><td>java.lang.Byte</td>\r
+<tr><td>java.lang.Byte</td><td>byte</td>\r
 <td>TINYINT</td></tr>\r
        \r
-<tr><td>java.lang.Short</td>\r
+<tr><td>java.lang.Short</td><td>short</td>\r
 <td>SMALLINT</td></tr>\r
        \r
-<tr><td>java.lang.Integer</td>\r
+<tr><td>java.lang.Integer</td><td>int</td>\r
 <td>INT</td></tr>\r
        \r
-<tr><td>java.lang.Long</td>\r
+<tr><td>java.lang.Long</td><td>long</td>\r
 <td>BIGINT</td></tr>\r
        \r
-<tr><td>java.lang.Float</td>\r
+<tr><td>java.lang.Float</td><td>float</td>\r
 <td>REAL</td></tr>\r
        \r
-<tr><td>java.lang.Double</td>\r
+<tr><td>java.lang.Double</td><td>double</td>\r
 <td>DOUBLE</td></tr>\r
        \r
-<tr><td>java.math.BigDecimal</td>\r
+<tr><td>java.math.BigDecimal</td><td></td>\r
 <td>DECIMAL *(length == 0)* or DECIMAL(length,scale) *(length > 0)*</td></tr>\r
        \r
-<tr><td>java.sql.Date</td>\r
+<tr><td>java.sql.Date</td><td></td>\r
 <td>DATE</td></tr>\r
        \r
-<tr><td>java.sql.Time</td>\r
+<tr><td>java.sql.Time</td><td></td>\r
 <td>TIME</td></tr>\r
        \r
-<tr><td>java.sql.Timestamp</td>\r
+<tr><td>java.sql.Timestamp</td><td></td>\r
 <td>TIMESTAMP</td></tr>\r
 \r
-<tr><td>java.util.Date</td>\r
+<tr><td>java.util.Date</td><td></td>\r
 <td>TIMESTAMP</td></tr>\r
 \r
-<tr><td>java.lang.Enum.name()<br/>*default type*</td>\r
+<tr><td>java.lang.Enum.name()<br/>*default type*</td><td></td>\r
 <td>VARCHAR *(length > 0)* or CLOB *(length == 0)*<br/>*EnumType.NAME*</td></tr>\r
 \r
-<tr><td>java.lang.Enum.ordinal()</td>\r
+<tr><td>java.lang.Enum.ordinal()</td><td></td>\r
 <td>INT<br/>*EnumType.ORDINAL*</td></tr>\r
 \r
-<tr><td>java.lang.Enum implements<br/>*com.iciql.Iciql.EnumId.enumId()*</td>\r
+<tr><td>java.lang.Enum implements<br/>*com.iciql.Iciql.EnumId.enumId()*</td><td></td>\r
 <td>INT<br/>*EnumType.ENUMID*</td></tr>\r
 \r
-<tr><th colspan="2">H2 Database Types</th></tr>\r
-<tr><td>java.util.UUID</td>\r
+<tr><td colspan="3"><b>Partially Supported Types</b><br/>\r
+can not be directly referenced in an expression</td></tr>\r
+<tr><td>byte []</td><td></td>\r
+<td>BLOB</td><tr/>\r
+\r
+<tr><td colspan="3"><b>H2 Database Types</b><br/>\r
+fully supported when paired with an H2 database \r
+</td></tr>\r
+<tr><td>java.util.UUID</td><td></td>\r
 <td>UUID</td><tr/>\r
 \r
 </table>\r
@@ -74,70 +84,6 @@ The following data types can be used for all iciql expressions.
 The reverse lookup used for model generation, SQL type -> Java type, contains more mappings.<br/>\r
 Please consult the `com.iciql.ModelUtils` class for details. \r
 \r
-### Partially Supported Data Types\r
-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.\r
-\r
-<table>\r
-<tr><td>byte []</td>\r
-<td>BLOB</td></tr>\r
-\r
-<tr><td>boolean</td>\r
-<td>BIT</td></tr>\r
-       \r
-<tr><td>byte</td>\r
-<td>TINYINT</td></tr>\r
-       \r
-<tr><td>short</td>\r
-<td>SMALLINT</td></tr>\r
-       \r
-<tr><td>int</td>\r
-<td>INT</td></tr>\r
-       \r
-<tr><td>long</td>\r
-<td>BIGINT</td></tr>\r
-       \r
-<tr><td>float</td>\r
-<td>REAL</td></tr>\r
-       \r
-<tr><td>double</td>\r
-<td>DOUBLE</td></tr>\r
-\r
-</table>\r
-\r
-#### Partially Supported Data Types Example\r
-%BEGINCODE%\r
-class Primitives {\r
-    @IQColumn(primaryKey = true)\r
-    int id;\r
-        \r
-    @IQColumn\r
-    String name;\r
-        \r
-    public Primitives() {\r
-    }\r
-    \r
-    public Primitives(int id, String name) {\r
-        this.id = id;\r
-        this.name = name;\r
-    }    \r
-}\r
-    \r
-Primitives p = new Primitives();\r
-\r
-// the following expressions compile, but will throw iciql runtime exceptions\r
-db.from(p).where(p.id).is(100).selectFirst();\r
-db.from(p).where(p.id).atLeast(10).select();\r
-\r
-// the following expressions will work as expected\r
-db.from(p).select();\r
-db.from(p).where("id = ?", 100).selectFirst();\r
-db.from(p).where("id >= ?", 10).select();\r
-db.insert(new Primitives(150, "test"));\r
-db.update(new Primitives(150, "modified"));\r
-db.delete(new Primitives(150, "test"));\r
-%ENDCODE%\r
-\r
-\r
 ## Annotation Configuration\r
 The recommended approach to setup a model class is to annotate the class and field declarations.\r
 \r
index a0905e54affc33829e9db0112c73d6179344aa8b..22ebb2e608cc43998b55b40167910a34d62d982a 100644 (file)
@@ -7,6 +7,7 @@
 **%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 v4)\r
+- full support for primitives in all clauses\r
 - DECIMAL(length, scale) support\r
 - unspecified length String fields are now CLOB instead of TEXT.  dialects can intercept this and convert to another type. e.g. MySQL dialect can change CLOB to TEXT.\r
 - Boolean now maps to BOOLEAN instead of BIT\r
@@ -15,7 +16,7 @@
 - moved dialects back to main package\r
 - improved automatic dialect determination on pooled connections\r
 - moved create table and create index statement generation into dialects\r
-- added HSQL dialect.  HSQL fails 4 out of 49 unit tests: 2 failures are unimplemented merge, 1 has been filed as a bug in HSQL.\r
+- added HSQL dialect.  HSQL fails 4 out of 49 unit tests: 2 failures are unimplemented merge, and 1 has been filed as a [bug in HSQL](https://sourceforge.net/tracker/?func=detail&aid=3390047&group_id=23316&atid=378131).\r
 - added MySQL dialect.  untested.\r
 - renamed <b>_ iq_versions</b> table to *iq_versions* since leading _ character is troublesome for some databases.\r
 - @IQColumn(allowNull=true) -> @IQColumn(nullable=true)\r
index 5c2d2254177285d5e75947cc0a84603d6add9b77..699574d44cdd57bcbf3e69169db5bd65a1d3c5e9 100644 (file)
@@ -23,6 +23,7 @@ import java.sql.Clob;
 import java.sql.ResultSet;\r
 import java.sql.SQLException;\r
 import java.util.ArrayList;\r
+import java.util.Arrays;\r
 import java.util.HashMap;\r
 import java.util.IdentityHashMap;\r
 import java.util.List;\r
@@ -49,7 +50,7 @@ public class Query<T> {
        private ArrayList<SelectTable<T>> joins = Utils.newArrayList();\r
        private final IdentityHashMap<Object, SelectColumn<T>> aliasMap = Utils.newIdentityHashMap();\r
        private ArrayList<OrderExpression<T>> orderByList = Utils.newArrayList();\r
-       private Object[] groupByExpressions;\r
+       private ArrayList<Object> groupByExpressions = Utils.newArrayList();\r
        private long limit;\r
        private long offset;\r
 \r
@@ -148,10 +149,80 @@ public class Query<T> {
                return new UpdateColumnSet<T, A>(this, field);\r
        }\r
 \r
+       public UpdateColumnSet<T, Boolean> set(boolean field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Byte> set(byte field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Short> set(short field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Integer> set(int field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Long> set(long field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Float> set(float field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnSet<T, Double> set(double field) {\r
+               return setPrimitive(field);\r
+       }\r
+\r
+       private <A> UpdateColumnSet<T, A> setPrimitive(A field) {\r
+               A alias = getPrimitiveAliasByValue(field);\r
+               if (alias == null) {\r
+                       // this will result in an unmapped field exception\r
+                       return set(field);\r
+               }\r
+               return set(alias);\r
+       }\r
+\r
        public <A> UpdateColumnIncrement<T, A> increment(A field) {\r
                return new UpdateColumnIncrement<T, A>(this, field);\r
        }\r
 \r
+       public UpdateColumnIncrement<T, Byte> increment(byte field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+       \r
+       public UpdateColumnIncrement<T, Short> increment(short field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnIncrement<T, Integer> increment(int field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnIncrement<T, Long> increment(long field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnIncrement<T, Float> increment(float field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+\r
+       public UpdateColumnIncrement<T, Double> increment(double field) {\r
+               return incrementPrimitive(field);\r
+       }\r
+\r
+       private <A> UpdateColumnIncrement<T, A> incrementPrimitive(A field) {\r
+               A alias = getPrimitiveAliasByValue(field);\r
+               if (alias == null) {\r
+                       // this will result in an unmapped field exception\r
+                       return increment(field);\r
+               }\r
+               return increment(alias);\r
+       }\r
+\r
        public int update() {\r
                if (updateColumnDeclarations.size() == 0) {\r
                        throw new IciqlException("Missing set or increment call.");\r
@@ -249,6 +320,105 @@ public class Query<T> {
                return stat;\r
        }\r
 \r
+       /**\r
+        * Begin a primitive boolean field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive boolean field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Boolean> where(boolean x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive short field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive short field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Byte> where(byte x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive short field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive short field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Short> where(short x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive int field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive int field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Integer> where(int x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive long field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive long field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Long> where(long x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive float field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive float field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Float> where(float x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begin a primitive double field condition clause.\r
+        * \r
+        * @param x\r
+        *            the primitive double field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Double> where(double x) {\r
+               return wherePrimitive(x);\r
+       }\r
+\r
+       /**\r
+        * Begins a primitive field condition clause.\r
+        * \r
+        * @param value\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       private <A> QueryCondition<T, A> wherePrimitive(A value) {\r
+               A alias = getPrimitiveAliasByValue(value);\r
+               if (alias == null) {\r
+                       // this will result in an unmapped field exception\r
+                       return where(value);\r
+               }\r
+               return where(alias);\r
+       }\r
+\r
+       /**\r
+        * Begin an Object field condition clause.\r
+        * \r
+        * @param x\r
+        *            the mapped object to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
        public <A> QueryCondition<T, A> where(A x) {\r
                return new QueryCondition<T, A>(this, x);\r
        }\r
@@ -306,6 +476,48 @@ public class Query<T> {
                return this;\r
        }\r
 \r
+       public Query<T> orderBy(boolean field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(byte field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(short field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(int field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(long field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(float field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> orderBy(double field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       Query<T> orderByPrimitive(Object field) {\r
+               Object alias = getPrimitiveAliasByValue(field);\r
+               if (alias == null) {\r
+                       return orderBy(field);\r
+               }\r
+               return orderBy(alias);\r
+       }\r
+       \r
+       public Query<T> orderBy(Object expr) {\r
+               OrderExpression<T> e = new OrderExpression<T>(this, expr, false, false, false);\r
+               addOrderBy(e);\r
+               return this;\r
+       }\r
+       \r
        /**\r
         * Order by a number of columns.\r
         * \r
@@ -328,8 +540,49 @@ public class Query<T> {
                return this;\r
        }\r
 \r
+       public Query<T> groupBy(boolean field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(byte field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(short field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(int field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(long field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(float field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public Query<T> groupBy(double field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       Query<T> groupByPrimitive(Object field) {\r
+               Object alias = getPrimitiveAliasByValue(field);\r
+               if (alias == null) {\r
+                       return groupBy(field);\r
+               }\r
+               return groupBy(alias);\r
+       }\r
+       \r
+       public Query<T> groupBy(Object expr) {\r
+               groupByExpressions.add(expr);\r
+               return this;\r
+       }\r
+       \r
        public Query<T> groupBy(Object... groupBy) {\r
-               this.groupByExpressions = groupBy;\r
+               this.groupByExpressions.addAll(Arrays.asList(groupBy));\r
                return this;\r
        }\r
 \r
@@ -362,7 +615,7 @@ public class Query<T> {
                        addParameter(stat, alias, value);\r
                        return;\r
                }\r
-               SelectColumn<T> col = aliasMap.get(value);\r
+               SelectColumn<T> col = getColumnByReference(value);\r
                if (col != null) {\r
                        col.appendSQL(stat);\r
                        return;\r
@@ -402,7 +655,7 @@ public class Query<T> {
 \r
        private void addParameter(SQLStatement stat, Object alias, Object value) {\r
                if (alias != null && value.getClass().isEnum()) {\r
-                       SelectColumn<T> col = aliasMap.get(alias);\r
+                       SelectColumn<T> col = getColumnByReference(alias);\r
                        EnumType type = col.getFieldDefinition().enumType;\r
                        Enum<?> anEnum = (Enum<?>) value;\r
                        Object y = Utils.convertEnum(anEnum, type);\r
@@ -437,7 +690,7 @@ public class Query<T> {
                        join.appendSQLAsJoin(stat, this);\r
                }\r
                appendWhere(stat);\r
-               if (groupByExpressions != null) {\r
+               if (!groupByExpressions.isEmpty()) {\r
                        stat.appendSQL(" GROUP BY ");\r
                        int i = 0;\r
                        for (Object obj : groupByExpressions) {\r
@@ -493,8 +746,34 @@ public class Query<T> {
                return !joins.isEmpty();\r
        }\r
 \r
-       SelectColumn<T> getSelectColumn(Object obj) {\r
-               return aliasMap.get(obj);\r
+       /**\r
+        * This method returns a mapped Object field by its reference.\r
+        * \r
+        * @param obj\r
+        * @return\r
+        */\r
+       private SelectColumn<T> getColumnByReference(Object obj) {\r
+               SelectColumn<T> col = aliasMap.get(obj);\r
+               return col;\r
+       }\r
+\r
+       /**\r
+        * This method returns the alias of a mapped primitive field by its value.\r
+        * \r
+        * @param obj\r
+        * @return\r
+        */\r
+       @SuppressWarnings("unchecked")\r
+       <A> A getPrimitiveAliasByValue(A obj) {\r
+               for (Object alias : aliasMap.keySet()) {\r
+                       if (alias.equals(obj)) {\r
+                               SelectColumn<T> match = aliasMap.get(alias);\r
+                               if (match.getFieldDefinition().isPrimitive) {\r
+                                       return (A) alias;\r
+                               }\r
+                       }\r
+               }\r
+               return null;\r
        }\r
 \r
        void addOrderBy(OrderExpression<T> expr) {\r
index 9071b523d635d47190367ec4d0332da9515b999e..727285d3684c777b6fc45fbe2df1210c4e905521 100644 (file)
@@ -34,11 +34,189 @@ public class QueryWhere<T> {
                this.query = query;\r
        }\r
 \r
+       /**\r
+        * Specify an AND condition with a mapped primitive boolean.\r
+        * \r
+        * @param x\r
+        *            the primitive boolean field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Boolean> and(boolean x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive byte.\r
+        * \r
+        * @param x\r
+        *            the primitive byte field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Byte> and(byte x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive short.\r
+        * \r
+        * @param x\r
+        *            the primitive short field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Short> and(short x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive int.\r
+        * \r
+        * @param x\r
+        *            the primitive int field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Integer> and(int x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive long.\r
+        * \r
+        * @param x\r
+        *            the primitive long field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Long> and(long x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive float.\r
+        * \r
+        * @param x\r
+        *            the primitive float field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Float> and(float x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped primitive double.\r
+        * \r
+        * @param x\r
+        *            the primitive double field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Double> and(double x) {\r
+               return addPrimitive(ConditionAndOr.AND, x);\r
+       }\r
+\r
+       private <A> QueryCondition<T, A> addPrimitive(ConditionAndOr condition, A x) {\r
+               query.addConditionToken(condition);\r
+               A alias = query.getPrimitiveAliasByValue(x);\r
+               if (alias == null) {\r
+                       // this will result in an unmapped field exception\r
+                       return new QueryCondition<T, A>(query, x);\r
+               }\r
+               return new QueryCondition<T, A>(query, alias);\r
+       }\r
+\r
+       /**\r
+        * Specify an AND condition with a mapped Object field.\r
+        * \r
+        * @param x\r
+        *            the Object field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
        public <A> QueryCondition<T, A> and(A x) {\r
                query.addConditionToken(ConditionAndOr.AND);\r
                return new QueryCondition<T, A>(query, x);\r
        }\r
 \r
+       /**\r
+        * Specify an OR condition with a mapped primitive boolean.\r
+        * \r
+        * @param x\r
+        *            the primitive boolean field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Boolean> or(boolean x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive byte.\r
+        * \r
+        * @param x\r
+        *            the primitive byte field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Byte> or(byte x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive short.\r
+        * \r
+        * @param x\r
+        *            the primitive short field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Short> or(short x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive int.\r
+        * \r
+        * @param x\r
+        *            the primitive int field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Integer> or(int x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive long.\r
+        * \r
+        * @param x\r
+        *            the primitive long field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Long> or(long x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive float.\r
+        * \r
+        * @param x\r
+        *            the primitive float field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Float> or(float x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped primitive double.\r
+        * \r
+        * @param x\r
+        *            the primitive double field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
+       public QueryCondition<T, Double> or(double x) {\r
+               return addPrimitive(ConditionAndOr.OR, x);\r
+       }\r
+\r
+       /**\r
+        * Specify an OR condition with a mapped Object field.\r
+        * \r
+        * @param x\r
+        *            the Object field to query\r
+        * @return a query condition to continue building the condition\r
+        */\r
        public <A> QueryCondition<T, A> or(A x) {\r
                query.addConditionToken(ConditionAndOr.OR);\r
                return new QueryCondition<T, A>(query, x);\r
@@ -88,7 +266,86 @@ public class QueryWhere<T> {
        }\r
 \r
        /**\r
-        * Order by a number of columns.\r
+        * Order by primitive boolean field\r
+        * \r
+        * @param field\r
+        *            a primitive boolean field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(boolean field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       /**\r
+        * Order by primitive byte field\r
+        * \r
+        * @param field\r
+        *            a primitive byte field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(byte field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       /**\r
+        * Order by primitive short field\r
+        * \r
+        * @param field\r
+        *            a primitive short field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(short field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       public QueryWhere<T> orderBy(int field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       /**\r
+        * Order by primitive long field\r
+        * \r
+        * @param field\r
+        *            a primitive long field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(long field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       /**\r
+        * Order by primitive float field\r
+        * \r
+        * @param field\r
+        *            a primitive float field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(float field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       /**\r
+        * Order by primitive double field\r
+        * \r
+        * @param field\r
+        *            a primitive double field\r
+        * @return the query\r
+        */\r
+       public QueryWhere<T> orderBy(double field) {\r
+               return orderByPrimitive(field);\r
+       }\r
+\r
+       private QueryWhere<T> orderByPrimitive(Object field) {\r
+               query.orderByPrimitive(field);\r
+               return this;\r
+       }\r
+\r
+       public QueryWhere<T> orderBy(Object field) {\r
+               query.orderBy(field);\r
+               return this;\r
+       }\r
+       /**\r
+        * Order by a number of Object columns.\r
         * \r
         * @param expressions\r
         *            the order by expressions\r
@@ -96,10 +353,7 @@ public class QueryWhere<T> {
         */\r
 \r
        public QueryWhere<T> orderBy(Object... expressions) {\r
-               for (Object expr : expressions) {\r
-                       OrderExpression<T> e = new OrderExpression<T>(query, expr, false, false, false);\r
-                       query.addOrderBy(e);\r
-               }\r
+               query.orderBy(expressions);\r
                return this;\r
        }\r
 \r
index 571ab1fed8681fb307b791a6ed7ab687b9846da8..687ba53fd90ca74e9b556c85958494a6be7a9792 100644 (file)
@@ -79,6 +79,7 @@ public class TableDefinition<T> {
                boolean nullable;\r
                String defaultValue;\r
                EnumType enumType;\r
+               boolean isPrimitive;\r
 \r
                Object getValue(Object obj) {\r
                        try {\r
@@ -345,6 +346,7 @@ public class TableDefinition<T> {
                        boolean reflectiveMatch = isPublic && !byAnnotationsOnly;\r
                        if (reflectiveMatch || hasAnnotation) {\r
                                FieldDefinition fieldDef = new FieldDefinition();\r
+                               fieldDef.isPrimitive = f.getType().isPrimitive();\r
                                fieldDef.field = f;\r
                                fieldDef.columnName = columnName;\r
                                fieldDef.isAutoIncrement = isAutoIncrement;\r
@@ -658,14 +660,4 @@ public class TableDefinition<T> {
                        query.appendSQL(stat, x, obj);\r
                }\r
        }\r
-\r
-       <Y, X> void copyAttributeValues(Query<Y> query, X to, X map) {\r
-               for (FieldDefinition def : fields) {\r
-                       Object obj = def.getValue(map);\r
-                       SelectColumn<Y> col = query.getSelectColumn(obj);\r
-                       Object value = col.getCurrentValue();\r
-                       def.setValue(to, value);\r
-               }\r
-       }\r
-\r
 }\r
index 6f9746d5c04e0949a0d59b4672afe30b9556e095..d9e065c19d03abcdcd07a42512fcd8bbacbe1fb3 100644 (file)
@@ -140,6 +140,7 @@ public class Utils {
                } else if (clazz == double.class || clazz == Double.class) {\r
                        return (T) new Double(COUNTER.getAndIncrement());\r
                } else if (clazz == boolean.class || clazz == Boolean.class) {\r
+                       COUNTER.getAndIncrement();\r
                        return (T) new Boolean(false);\r
                } else if (clazz == BigDecimal.class) {\r
                        return (T) new BigDecimal(COUNTER.getAndIncrement());\r
@@ -154,12 +155,15 @@ public class Utils {
                } else if (clazz == java.util.Date.class) {\r
                        return (T) new java.util.Date(COUNTER.getAndIncrement());\r
                } else if (clazz == byte[].class) {\r
+                       COUNTER.getAndIncrement();\r
                        return (T) new byte[0];\r
                } else if (clazz.isEnum()) {\r
+                       COUNTER.getAndIncrement();\r
                        // enums can not be instantiated reflectively\r
                        // return first constant as reference\r
                        return clazz.getEnumConstants()[0];\r
                } else if (clazz == java.util.UUID.class) {\r
+                       COUNTER.getAndIncrement();\r
                        return (T) UUID.randomUUID();\r
                }\r
                try {\r
index f0d5c153e747c6143eb09d391e481f1179177003..0f91365e6a6caa8e6680df6e62110a8081a4c416 100644 (file)
 package com.iciql.test;
 
 import static org.junit.Assert.assertEquals;
-
-import java.util.List;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
 import com.iciql.Db;
+import com.iciql.IciqlException;
+import com.iciql.test.models.PrimitivesModel;
 import com.iciql.test.models.Product;
+import com.iciql.util.Utils;
 
 /**
- * Tests that columns (p.unitsInStock) are not compared by value with the value
- * (9), but by reference (using an identity hash map). See
- * http://code.google.com/p/h2database/issues/detail?id=119
- * 
- * @author d moebius at scoop dash gmbh dot de
+ * Tests object and primitive alias referencing.
  */
 public class AliasMapTest {
 
+       /**
+        * Tests that columns (p.unitsInStock) are not compared by value with the
+        * value (9), but by reference (using an identity hash map). See
+        * http://code.google.com/p/h2database/issues/detail?id=119
+        * 
+        * @author d moebius at scoop dash gmbh dot de
+        */
        @Test
-       public void testAliasMapping() throws Exception {
+       public void testObjectAliasMapping() throws Exception {
                Db db = IciqlSuite.openDb();
                db.insertAll(Product.getList());
 
+               // baseline count is the next id value
+               long bc = Utils.COUNTER.get();
+               // number of fields in primitives model class
+               // each from() call will increment Utils.COUNTER by this amount
+               int fc = Product.class.getFields().length;
+
                Product p = new Product();
-               List<Product> products = db.from(p).where(p.unitsInStock).is(9).orderBy(p.productId).select();
+               // This test confirms standard object referencing querying.
+               long count = db.from(p).where(p.productId).is(9).selectCount();
+               assertEquals(1, count);
+               // Confirms that productId counter value is baseline counter value
+               assertEquals(bc, p.productId.intValue());
+               try {
+                       // This test compares "bc + fc" which is the counter value of
+                       // unitsInStock assigned by Utils.newObject() after the 2nd pass
+                       // through from().
+                       //
+                       // Object fields map by REFERENCE, not value.
+                       db.from(p).where(Long.valueOf(bc + fc).intValue()).is(9).orderBy(p.productId).select();
+                       assertTrue("Fail: object field is mapping by value.", false);
+               } catch (IciqlException e) {
+                       assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode());
+                       assertEquals(bc + 5, p.productId.intValue());
+               }
+
+               try {
+                       // This test compares Integer(bc) which is the counter value of
+                       // unitsInStock assigned by Utils.newObject() after the 3rd pass
+                       // through from().
+                       //
+                       // Object fields map by REFERENCE, not value.
+                       db.from(p).where(Long.valueOf(bc).intValue()).is(9).orderBy(p.productId).select();
+                       assertTrue("Fail: object field is mapping by value.", false);
+               } catch (IciqlException e) {
+                       assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode());
+                       assertEquals(bc + (2 * fc), p.productId.intValue());
+               }
+
+               db.close();
+       }
+
+       /**
+        * Confirms that primitive aliases ARE mapped by value.
+        */
+       @Test
+       public void testPrimitiveAliasMapping() throws Exception {
+               Db db = IciqlSuite.openDb();
+               PrimitivesModel model = new PrimitivesModel();
+               model.myLong = 100L;
+               db.insert(model);
+               model.myLong = 200L;
+               db.insert(model);
 
-               assertEquals("[]", products.toString());
+               // baseline count is the next id value
+               long bc = Utils.COUNTER.get();
+               // number of fields in primitives model class
+               // each from() call will increment Utils.COUNTER by this amount
+               int fc = PrimitivesModel.class.getFields().length;
 
+               PrimitivesModel p = new PrimitivesModel();
+               // This test confirms standard primitive referencing querying.
+               long count = db.from(p).where(p.myLong).is(100L).selectCount();
+               assertEquals(1, count);
+               // Confirms that myLong counter value is bc
+               assertEquals(bc, p.myLong);
+               try {
+                       // This test compares "bc + fc" which is the counter value
+                       // of myLong assigned by Utils.newObject() after the 2nd pass
+                       // through from().
+                       //
+                       // Primitive fields map by VALUE.
+                       count = db.from(p).where(bc + fc).is(100L).selectCount();
+                       assertEquals(1, count);
+                       assertEquals(bc + fc, p.myLong);
+               } catch (IciqlException e) {
+                       assertTrue(e.getMessage(), false);
+               }
+               try {
+                       // This test compares "bc" which was the counter value of
+                       // myLong assigned by Utils.newObject() after the 1st pass
+                       // through from(). "bc" is unmapped now and will throw an
+                       // exception.
+                       //
+                       // Primitive fields map by VALUE.
+                       db.from(p).where(bc).is(100L).select();
+               } catch (IciqlException e) {
+                       assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode());
+                       assertEquals(bc + (2 * fc), p.myLong);
+               }
                db.close();
        }
 }
\ No newline at end of file
index 1cdeb1c77052b22423f6f2aa5f59e4257fa95e9b..a200b57ab139a914782c807f7f15efe681b6f769 100644 (file)
 \r
 package com.iciql.test;\r
 \r
+import static org.junit.Assert.assertEquals;\r
 import static org.junit.Assert.assertTrue;\r
 \r
+import java.util.Collections;\r
+import java.util.List;\r
+\r
 import org.junit.Test;\r
 \r
 import com.iciql.Db;\r
@@ -32,14 +36,17 @@ public class PrimitivesTest {
        public void testPrimitives() {\r
                Db db = IciqlSuite.openDb();\r
 \r
-               // insert random model\r
-               PrimitivesModel model = new PrimitivesModel();\r
-               db.insert(model);\r
+               // insert random models in reverse order\r
+               List<PrimitivesModel> models = PrimitivesModel.getList();\r
+               PrimitivesModel model = models.get(0);\r
+               Collections.reverse(models);\r
+               // insert them in reverse order\r
+               db.insertAll(models);\r
 \r
                PrimitivesModel p = new PrimitivesModel();\r
 \r
                // retrieve model and compare\r
-               PrimitivesModel retrievedModel = db.from(p).selectFirst();\r
+               PrimitivesModel retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();\r
                assertTrue(model.equivalentTo(retrievedModel));\r
 \r
                retrievedModel = db.from(p).where("mylong = ? and myinteger = ?", model.myLong, model.myInteger)\r
@@ -47,17 +54,26 @@ public class PrimitivesTest {
                assertTrue(model.equivalentTo(retrievedModel));\r
 \r
                // retrieve with conditions and compare\r
-               // StatementLogger.activateConsoleLogger();\r
-               // retrievedModel =\r
-               // db.from(p).where(p.myLong).is(model.myLong).and(p.myInteger).is(model.myInteger)\r
-               // .selectFirst();\r
-               // assertTrue(model.equivalentTo(retrievedModel));\r
-               //\r
-               // // update myInteger and compare\r
-               // db.from(p).set(p.myInteger).to(10).where(p.myLong).is(model.myLong).update();\r
-               // retrievedModel = db.from(p).selectFirst();\r
-\r
-               // assertEquals(10, retrievedModel.myInteger);\r
+               retrievedModel = db.from(p).where(p.myLong).is(model.myLong).and(p.myInteger).is(model.myInteger)\r
+                               .selectFirst();\r
+               assertTrue(model.equivalentTo(retrievedModel));\r
+\r
+               // set myInteger & myDouble\r
+               db.from(p).set(p.myInteger).to(10).set(p.myDouble).to(3.0d).where(p.myLong).is(model.myLong).update();\r
+               retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();\r
+\r
+               assertEquals(10, retrievedModel.myInteger);\r
+               assertEquals(3d, retrievedModel.myDouble, 0.001d);\r
+\r
+               // increment my double by pi\r
+               db.from(p).increment(p.myDouble).by(3.14d).update();\r
+               retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();\r
+               assertEquals(6.14d, retrievedModel.myDouble, 0.001d);\r
+\r
+               // test order by\r
+               List<PrimitivesModel> list = db.from(p).orderBy(p.myLong).select();\r
+               assertEquals(models.size(), list.size());\r
+               assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", list.toString());\r
 \r
                db.close();\r
        }\r
index 2d1a7da99dba7367cc03d8f00687a7029fe35906..07c161174dec17a7015d70d9af21f0df9d6789ce 100644 (file)
@@ -15,6 +15,8 @@
  */\r
 package com.iciql.test.models;\r
 \r
+import java.util.ArrayList;\r
+import java.util.List;\r
 import java.util.Random;\r
 \r
 import com.iciql.Iciql.IQColumn;\r
@@ -69,4 +71,19 @@ public class PrimitivesModel {
                same &= myFloat == p.myFloat;\r
                return same;\r
        }\r
+\r
+       public static List<PrimitivesModel> getList() {\r
+               List<PrimitivesModel> list = new ArrayList<PrimitivesModel>();\r
+               for (int i = 1; i <= 10; i++) {\r
+                       PrimitivesModel p = new PrimitivesModel();\r
+                       p.myLong = i;\r
+                       list.add(p);\r
+               }\r
+               return list;\r
+       }\r
+       \r
+       @Override\r
+       public String toString() {\r
+               return String.valueOf(myLong);\r
+       }\r
 }\r