<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
<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
@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
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
### 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%)) *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
%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
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
* <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
* </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
/**\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
* <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
* 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
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
}\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
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
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
--- /dev/null
+/*\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
* \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
true);
assertEquals(1, models.size());
// a poor test, but a start
- assertEquals(1904, models.get(0).length());
+ assertEquals(1895, models.get(0).length());
}
@Test
--- /dev/null
+/*\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
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
public void defineIQ() {\r
tableName("Product");\r
primaryKey(productId);\r
- maxLength(category, 255);\r
+ length(category, 255);\r
index(productName, category);\r
}\r
\r
@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")
public Integer unitsInStock;
public String mappedField;
- @IQColumn(name = "cat", maxLength = 255)
+ @IQColumn(name = "cat", length = 255)
public String category;
@IQColumn(name = "id", primaryKey = true)
public Integer id;
@IQColumn
- private Boolean myBool = false;
+ private Boolean myBool;
@IQColumn
- private Byte myByte = 2;
+ private Byte myByte;
@IQColumn
private Short myShort;
private Long myLong;
@IQColumn
- private Float myFloat = 1.0f;
+ private Float myFloat;
@IQColumn
private Double myDouble;
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;