]> source.dussan.org Git - iciql.git/commitdiff
Simplified annotations. Interchangeable int-boolean runtime mapping.
authorJames Moger <james.moger@gmail.com>
Fri, 5 Aug 2011 15:04:29 +0000 (11:04 -0400)
committerJames Moger <james.moger@gmail.com>
Fri, 5 Aug 2011 15:04:29 +0000 (11:04 -0400)
16 files changed:
docs/01_model_classes.mkd
docs/05_releases.mkd
src/com/iciql/Define.java
src/com/iciql/Iciql.java
src/com/iciql/Query.java
src/com/iciql/TableDefinition.java
src/com/iciql/TableInspector.java
src/com/iciql/util/Utils.java
tests/com/iciql/test/BooleanModelTest.java [new file with mode: 0644]
tests/com/iciql/test/IciqlSuite.java
tests/com/iciql/test/ModelsTest.java
tests/com/iciql/test/models/BooleanModel.java [new file with mode: 0644]
tests/com/iciql/test/models/Product.java
tests/com/iciql/test/models/ProductAnnotationOnly.java
tests/com/iciql/test/models/ProductMixedAnnotation.java
tests/com/iciql/test/models/SupportedTypes.java

index bf8d72cf97b3d13e98375e1802f9e8e231150bd5..fb81e0f41650bbcc52361f7f1e87e2eb7f6e49d0 100644 (file)
@@ -9,7 +9,7 @@ Alternatively, model classes can be automatically generated by iciql using the m
 <table>\r
 \r
 <tr><td>java.lang.String</td>\r
-<td>VARCHAR *(maxLength > 0)* or TEXT *(maxLength == 0)*</td></tr>\r
+<td>VARCHAR *(length > 0)* or TEXT *(length == 0)*</td></tr>\r
        \r
 <tr><td>java.lang.Boolean</td>\r
 <td>BIT</td></tr>\r
@@ -51,7 +51,7 @@ Alternatively, model classes can be automatically generated by iciql using the m
 <td>BLOB</td></tr>\r
 \r
 <tr><td>java.lang.Enum.name()</td>\r
-<td>VARCHAR (maxLength > 0) or TEXT (maxLength == 0)<br/>EnumType.STRING</td></tr>\r
+<td>VARCHAR (length > 0) or TEXT (length == 0)<br/>EnumType.STRING</td></tr>\r
 \r
 <tr><td>java.lang.Enum.ordinal()</td>\r
 <td>INT<br/>EnumType.ORDINAL</td></tr>\r
@@ -115,10 +115,10 @@ public class Product {
        @IQColumn(primaryKey = true)\r
        public Integer productId;\r
       \r
-       @IQColumn(maxLength = 200, trimString = true)\r
+       @IQColumn(length = 200, trim = true)\r
        public String productName;\r
       \r
-       @IQColumn(maxLength = 50, trimString = true)\r
+       @IQColumn(length = 50, trim = true)\r
        public String category;\r
       \r
        @IQColumn\r
@@ -185,8 +185,8 @@ public class Product implements Iciql {
        public void defineIQ() {\r
                com.iciql.Define.primaryKey(productId);\r
                com.iciql.Define.columnName(unitsInStock, "units");\r
-               com.iciql.Define.maxLength(productName, 200);\r
-               com.iciql.Define.maxLength(category, 50);\r
+               com.iciql.Define.length(productName, 200);\r
+               com.iciql.Define.length(category, 50);\r
                com.iciql.Define.index(productName, category);\r
        }\r
 }\r
index 50fda43efa9ca89eef2311a0ca71eda8c9013eb5..d04fbea2f46294b2894062a11efbfeafdccc9d35 100644 (file)
@@ -3,9 +3,11 @@
 ### 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
 - added BLOB support (issue 1)\r
 - added java.lang.Enum support (issue 2)\r
-- api change release (API v2)\r
+- allow runtime flexible mapping of BOOL columns to Integer fields\r
+- allow runtime flexible mapping of INT columns to Boolean fields\r
 - annotations overhaul to reduce verbosity\r
     - @IQSchema(name="public") -> @IQSchema("public")\r
     - @IQDatabase(version=2) -> @IQVersion(2)\r
@@ -15,6 +17,8 @@
 %BEGINCODE%\r
 @IQIndexes({ @IQIndex("name"), @IQIndex(name="myindexname" value={"name", "nickname"}) })\r
 %ENDCODE%\r
+    - @IQColumn(maxLength=20) -> @IQColumn(length=20)\r
+    - @IQColumn(trimString=true) -> @IQColumn(trim=true)\r
 \r
 ### Older Releases\r
 \r
index 54e435fa53c3b2d699e1e8814c9116373b15abf6..d7b42ba690e0712b092a21a339a143e0aea58fc4 100644 (file)
@@ -59,7 +59,7 @@ public class Define {
                currentTableDefinition.setColumnName(column, columnName);\r
        }\r
 \r
-       public static void maxLength(Object column, int length) {\r
+       public static void length(Object column, int length) {\r
                checkInDefine();\r
                currentTableDefinition.setMaxLength(column, length);\r
        }\r
index ff2452ee2bf627e16a22e6b1d47f7da2bfdec0ab..6abe97de97ff66644c9e353851f4f63c85bd7953 100644 (file)
@@ -37,7 +37,7 @@ import java.lang.annotation.Target;
  * <table>\r
  * <tr>\r
  * <td>java.lang.String</td>\r
- * <td>VARCHAR (maxLength > 0) or TEXT (maxLength == 0)</td>\r
+ * <td>VARCHAR (length > 0) or TEXT (length == 0)</td>\r
  * </tr>\r
  * <tr>\r
  * <td>java.lang.Boolean</td>\r
@@ -93,15 +93,19 @@ import java.lang.annotation.Target;
  * </tr>\r
  * <tr>\r
  * <td>java.lang.Enum.name()</td>\r
- * <td>VARCHAR (maxLength > 0) or TEXT (maxLength == 0)<br/>EnumType.STRING</td>\r
+ * <td>VARCHAR (length > 0) or TEXT (length == 0)<br/>\r
+ * EnumType.STRING</td>\r
  * </tr>\r
  * <tr>\r
  * <td>java.lang.Enum.ordinal()</td>\r
- * <td>INT<br/>EnumType.ORDINAL</td>\r
+ * <td>INT<br/>\r
+ * EnumType.ORDINAL</td>\r
  * </tr>\r
  * <tr>\r
- * <td>java.lang.Enum implements<br/>com.iciql.Iciql.EnumID.enumId()</td>\r
- * <td>INT<br/>EnumType.ENUMID</td>\r
+ * <td>java.lang.Enum implements<br/>\r
+ * com.iciql.Iciql.EnumID.enumId()</td>\r
+ * <td>INT<br/>\r
+ * EnumType.ENUMID</td>\r
  * </tr>\r
  * </tr>\r
  * </table>\r
@@ -346,18 +350,18 @@ public interface Iciql {
                /**\r
                 * If larger than zero, it is used during the CREATE TABLE phase. It may\r
                 * also be used to prevent database exceptions on INSERT and UPDATE\r
-                * statements (see trimString).\r
+                * statements (see trim).\r
                 * <p>\r
-                * Any maxLength set in define() may override this annotation setting if\r
+                * Any length set in define() may override this annotation setting if\r
                 * the model class is not annotated with IQTable. Default: 0.\r
                 */\r
-               int maxLength() default 0;\r
+               int length() default 0;\r
 \r
                /**\r
                 * If true, iciql will automatically trim the string if it exceeds\r
-                * maxLength (value.substring(0, maxLength)). Default: false.\r
+                * length (value.substring(0, length)). Default: false.\r
                 */\r
-               boolean trimString() default false;\r
+               boolean trim() default false;\r
 \r
                /**\r
                 * If false, iciql will set the column NOT NULL during the CREATE TABLE\r
@@ -403,7 +407,8 @@ public interface Iciql {
         * <li>ORDINAL - ordinal() : int\r
         * <li>ENUMID - enumId() : int\r
         * </ul>\r
-        *  @see com.iciql.Iciql.EnumId interface\r
+        * \r
+        * @see com.iciql.Iciql.EnumId interface\r
         */\r
        public enum EnumType {\r
                STRING, ORDINAL, ENUMID;\r
@@ -428,8 +433,8 @@ public interface Iciql {
         * IQEnum(EnumType.STRING)\r
         * </pre>\r
         * \r
-        * A string mapping will generate either a VARCHAR, if IQColumn.maxLength >\r
-        * 0 or a TEXT column if IQColumn.maxLength == 0\r
+        * A string mapping will generate either a VARCHAR, if IQColumn.length >\r
+        * 0 or a TEXT column if IQColumn.length == 0\r
         * \r
         */\r
        @Retention(RetentionPolicy.RUNTIME)\r
index d9dc84f8c9a090995d898e82369cb6f8a748b087..0611ffac92e7f50f0f4bb5d7dd1465e05c293257 100644 (file)
@@ -222,6 +222,7 @@ public class Query<T> {
                                try {\r
                                        X value;\r
                                        Object o = rs.getObject(1);\r
+                                       // Convert CLOB and BLOB now because we close the resultset\r
                                        if (Clob.class.isAssignableFrom(o.getClass())) {\r
                                                value = (X) Utils.convert(o, String.class);\r
                                        } else if (Blob.class.isAssignableFrom(o.getClass())) {\r
index 72b53482cabff45152e7b9e32507658207d35e0e..5d9b9c4a0d41d5754075d3cad3b47d60a9818c17 100644 (file)
@@ -285,8 +285,8 @@ class TableDefinition<T> {
                                }\r
                                isAutoIncrement = col.autoIncrement();\r
                                isPrimaryKey = col.primaryKey();\r
-                               maxLength = col.maxLength();\r
-                               trimString = col.trimString();\r
+                               maxLength = col.length();\r
+                               trimString = col.trim();\r
                                allowNull = col.allowNull();\r
                                defaultValue = col.defaultValue();\r
                        }\r
index 879e23a25c8a813f25ab64df9066bd24651a2fd8..82b732ab5801c9fd1ac67da6f614286cccd8cb98 100644 (file)
@@ -346,13 +346,13 @@ public class TableInspector {
                                ap.addParameter("primaryKey=true");
                        }
 
-                       // IQColumn.maxLength
+                       // IQColumn.length
                        if ((clazz == String.class) && (col.size > 0) && (col.size < Integer.MAX_VALUE)) {
-                               ap.addParameter("maxLength", col.size);
+                               ap.addParameter("length", col.size);
 
-                               // IQColumn.trimStrings
+                               // IQColumn.trim
                                if (trimStrings) {
-                                       ap.addParameter("trimString=true");
+                                       ap.addParameter("trim=true");
                                }
                        } else {
                                // IQColumn.AutoIncrement
index 302dd4d14ef25746c112816a043ebe3c6030b055..dac30fcdb643c13c563debf73a3b9c0a3a18efb6 100644 (file)
@@ -226,6 +226,22 @@ public class Utils {
                        return o.toString();\r
                }\r
 \r
+               // convert from number to boolean\r
+               if (Boolean.class.isAssignableFrom(targetType)) {\r
+                       if (Number.class.isAssignableFrom(currentType)) {\r
+                               Number n = (Number) o;\r
+                               return n.intValue() > 0;\r
+                       }\r
+               }\r
+\r
+               // convert from boolean to number\r
+               if (Boolean.class.isAssignableFrom(currentType)) {\r
+                       if (Number.class.isAssignableFrom(targetType)) {\r
+                               Boolean b = (Boolean) o;\r
+                               return b ? 1 : 0;\r
+                       }\r
+               }\r
+\r
                // convert from number to number\r
                if (Number.class.isAssignableFrom(currentType)) {\r
                        Number n = (Number) o;\r
diff --git a/tests/com/iciql/test/BooleanModelTest.java b/tests/com/iciql/test/BooleanModelTest.java
new file mode 100644 (file)
index 0000000..0287e06
--- /dev/null
@@ -0,0 +1,128 @@
+/*\r
+ * Copyright 2011 James Moger.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\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.List;\r
+\r
+import org.junit.Test;\r
+\r
+import com.iciql.Db;\r
+import com.iciql.test.models.BooleanModel;\r
+import com.iciql.test.models.BooleanModel.BooleanAsIntModel;\r
+\r
+/**\r
+ * Tests interchangeable mapping of INT columns with Booleans and BOOL columns\r
+ * with Integers.\r
+ * <ul>\r
+ * <li>mapping a BIT/BOOLEAN column as an Integer\r
+ * <li>mapping a INT column as a Boolean.\r
+ * </ul>\r
+ */\r
+public class BooleanModelTest {\r
+\r
+       @Test\r
+       public void testBooleanColumn() {\r
+               Db db = Db.open("jdbc:h2:mem:", "sa", "sa");\r
+               db.insertAll(BooleanModel.getList());\r
+               BooleanAsIntModel b = new BooleanAsIntModel();\r
+               List<BooleanAsIntModel> models = db.from(b).select();\r
+               int count = 0;\r
+               for (BooleanAsIntModel model : models) {\r
+                       if ((model.id % 2) == 1) {\r
+                               // assert that odd ids are true\r
+                               assertTrue(model.mybool > 0);\r
+                       } else {\r
+                               // assert that even ids are false\r
+                               assertTrue(model.mybool == 0);\r
+                       }\r
+\r
+                       // count true values\r
+                       if (model.mybool > 0) {\r
+                               count++;\r
+                       }\r
+               }\r
+               assertEquals(2, count);\r
+\r
+               // invert boolean values and update\r
+               for (BooleanAsIntModel model : models) {\r
+                       model.mybool = model.mybool > 0 ? 0 : 1;\r
+               }\r
+               db.updateAll(models);\r
+\r
+               // check even ids are true\r
+               models = db.from(b).select();\r
+               for (BooleanAsIntModel model : models) {\r
+                       if ((model.id % 2) == 1) {\r
+                               // assert that odd ids are false\r
+                               assertTrue(model.mybool == 0);\r
+                       } else {\r
+                               // assert that even ids are true\r
+                               assertTrue(model.mybool > 0);\r
+                       }\r
+               }\r
+               db.close();\r
+       }\r
+\r
+       @Test\r
+       public void testIntColumn() {\r
+               Db db = Db.open("jdbc:h2:mem:", "sa", "sa");\r
+               // insert INT column\r
+               db.insertAll(BooleanAsIntModel.getList());\r
+\r
+               // select all rows with INT column and map to Boolean\r
+               BooleanModel b = new BooleanModel();\r
+               List<BooleanModel> models = db.from(b).select();\r
+               int count = 0;\r
+               for (BooleanModel model : models) {\r
+                       if ((model.id % 2) == 1) {\r
+                               // assert that odd ids are true\r
+                               assertTrue(model.mybool);\r
+                       } else {\r
+                               // assert that even ids are false\r
+                               assertTrue(!model.mybool);\r
+                       }\r
+\r
+                       // count true values\r
+                       if (model.mybool) {\r
+                               count++;\r
+                       }\r
+               }\r
+               assertEquals(2, count);\r
+\r
+               // invert boolean values and update\r
+               for (BooleanModel model : models) {\r
+                       model.mybool = !model.mybool;\r
+               }\r
+               db.updateAll(models);\r
+\r
+               // check even ids are true\r
+               models = db.from(b).select();\r
+               for (BooleanModel model : models) {\r
+                       if ((model.id % 2) == 1) {\r
+                               // assert that odd ids are false\r
+                               assertTrue(!model.mybool);\r
+                       } else {\r
+                               // assert that even ids are true\r
+                               assertTrue(model.mybool);\r
+                       }\r
+               }\r
+               db.close();\r
+       }\r
+}\r
index b235f6dd2253efe75c8c4da6244b8b0d4a4487ef..20dbea25cf55d37fecad519f60a0741f3b6a9ca9 100644 (file)
@@ -25,8 +25,8 @@ import org.junit.runners.Suite.SuiteClasses;
  * \r
  */\r
 @RunWith(Suite.class)\r
-@SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, ClobTest.class, ConcurrencyTest.class,\r
-               ModelsTest.class, SamplesTest.class, UpdateTest.class, RuntimeQueryTest.class,\r
+@SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, BooleanModelTest.class, ClobTest.class,\r
+               ConcurrencyTest.class, ModelsTest.class, SamplesTest.class, UpdateTest.class, RuntimeQueryTest.class,\r
                StatementLoggerTest.class })\r
 public class IciqlSuite {\r
 \r
index 716b1bc50c003ce72953784aa7e22400fd996c5b..90122965b953f06f07d74e353efa03964997b5e7 100644 (file)
@@ -115,7 +115,7 @@ public class ModelsTest {
                                true);
                assertEquals(1, models.size());
                // a poor test, but a start
-               assertEquals(1904, models.get(0).length());
+               assertEquals(1895, models.get(0).length());
        }
 
        @Test
diff --git a/tests/com/iciql/test/models/BooleanModel.java b/tests/com/iciql/test/models/BooleanModel.java
new file mode 100644 (file)
index 0000000..d22e3c1
--- /dev/null
@@ -0,0 +1,73 @@
+/*\r
+ * Copyright 2011 James Moger.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.iciql.test.models;\r
+\r
+import java.util.Arrays;\r
+import java.util.List;\r
+\r
+import com.iciql.Iciql.IQColumn;\r
+import com.iciql.Iciql.IQTable;\r
+\r
+/**\r
+ * Boolean types model.\r
+ */\r
+@IQTable(name = "BooleanTest")\r
+public class BooleanModel {\r
+\r
+       @IQColumn(primaryKey = true)\r
+       public Integer id;\r
+\r
+       @IQColumn\r
+       public Boolean mybool;\r
+\r
+       public BooleanModel() {\r
+       }\r
+\r
+       BooleanModel(int id, boolean val) {\r
+               this.id = id;\r
+               this.mybool = val;\r
+       }\r
+\r
+       public static List<BooleanModel> getList() {\r
+               return Arrays.asList(new BooleanModel(1, true), new BooleanModel(2, false),\r
+                               new BooleanModel(3, true), new BooleanModel(4, false));\r
+       }\r
+\r
+       /**\r
+        * Test boolean as int\r
+        */\r
+       @IQTable(name = "BooleanTest")\r
+       public static class BooleanAsIntModel {\r
+               @IQColumn(primaryKey = true)\r
+               public Integer id;\r
+\r
+               @IQColumn\r
+               public Integer mybool;\r
+\r
+               public BooleanAsIntModel() {\r
+               }\r
+\r
+               BooleanAsIntModel(int id, boolean val) {\r
+                       this.id = id;\r
+                       this.mybool = val ? 1 : 0;\r
+               }\r
+\r
+               public static List<BooleanAsIntModel> getList() {\r
+                       return Arrays.asList(new BooleanAsIntModel(1, true), new BooleanAsIntModel(2, false),\r
+                                       new BooleanAsIntModel(3, true), new BooleanAsIntModel(4, false));\r
+               }\r
+       }\r
+}\r
index 735ebab59e2f52c821b7ca70b3ff5909b97733ae..065e62462b3f7a58cc99195d636bd4b485d7dad9 100644 (file)
@@ -18,7 +18,7 @@
 package com.iciql.test.models;\r
 \r
 import static com.iciql.Define.index;\r
-import static com.iciql.Define.maxLength;\r
+import static com.iciql.Define.length;\r
 import static com.iciql.Define.primaryKey;\r
 import static com.iciql.Define.tableName;\r
 \r
@@ -54,7 +54,7 @@ public class Product implements Iciql {
        public void defineIQ() {\r
                tableName("Product");\r
                primaryKey(productId);\r
-               maxLength(category, 255);\r
+               length(category, 255);\r
                index(productName, category);\r
        }\r
 \r
index caf07c7a19d22231a433f46542946486417a81a5..673ca14f889de5119217dedbdf65a08691530412 100644 (file)
@@ -42,7 +42,7 @@ public class ProductAnnotationOnly {
        @IQColumn(name = "id")
        public Integer productId;
 
-       @IQColumn(name = "cat", maxLength = 15, trimString = true)
+       @IQColumn(name = "cat", length = 15, trim = true)
        public String category;
 
        @IQColumn(name = "name")
index 1d3cb8fbd126ec5a00926ad9c2f3799fed224cb0..ff7d46f9787ae719c1ce3ea4118a93127fc9511e 100644 (file)
@@ -36,7 +36,7 @@ public class ProductMixedAnnotation {
        public Integer unitsInStock;
        public String mappedField;
 
-       @IQColumn(name = "cat", maxLength = 255)
+       @IQColumn(name = "cat", length = 255)
        public String category;
 
        @IQColumn(name = "id", primaryKey = true)
index 97a867502d44c9f81acb372c0ec753bac234aed1..c8aebcb6d8043d44abd9175b9641120ca1aef06d 100644 (file)
@@ -80,10 +80,10 @@ public class SupportedTypes {
        public Integer id;
 
        @IQColumn
-       private Boolean myBool = false;
+       private Boolean myBool;
 
        @IQColumn
-       private Byte myByte = 2;
+       private Byte myByte;
 
        @IQColumn
        private Short myShort;
@@ -95,7 +95,7 @@ public class SupportedTypes {
        private Long myLong;
 
        @IQColumn
-       private Float myFloat = 1.0f;
+       private Float myFloat;
 
        @IQColumn
        private Double myDouble;
@@ -122,14 +122,14 @@ public class SupportedTypes {
        private byte[] myBlob;
 
        @IQEnum(EnumType.STRING)
-       @IQColumn(trimString = true, maxLength = 25)
+       @IQColumn(trim = true, length = 25)
        private Flower myFavoriteFlower;
 
        @IQEnum(EnumType.ORDINAL)
        @IQColumn
        private Flower myOtherFavoriteFlower;
 
-       @IQColumn(maxLength = 25)
+       @IQColumn(length = 25)
        // @IQEnum is set on the enumeration definition and is shared
        // by all uses of Tree as an @IQColumn
        private Tree myFavoriteTree;