]> source.dussan.org Git - iciql.git/commitdiff
Do not register DataTypeAdapters by the target Java type
authorJames Moger <james.moger@gitblit.com>
Mon, 11 May 2015 21:20:00 +0000 (17:20 -0400)
committerJames Moger <james.moger@gitblit.com>
Mon, 11 May 2015 21:20:00 +0000 (17:20 -0400)
build.moxie
releases.moxie
src/main/java/com/iciql/DaoProxy.java
src/main/java/com/iciql/Query.java
src/main/java/com/iciql/SQLDialect.java
src/main/java/com/iciql/SQLDialectDefault.java
src/main/java/com/iciql/SQLDialectH2.java
src/main/java/com/iciql/SQLDialectHSQL.java
src/main/java/com/iciql/SQLDialectMySQL.java
src/main/java/com/iciql/SQLDialectSQLite.java
src/main/java/com/iciql/TableDefinition.java

index b70e2dbe54fd3bafb8c743b218645c623d3e2cda..5a69346740bcc7e339528c1451913462920b433b 100644 (file)
@@ -10,7 +10,7 @@ name: Iciql
 description: 'a model-based database access wrapper for JDBC'
 groupId: com.iciql
 artifactId: iciql
-version: 1.7.0-SNAPSHOT
+version: 1.6.2-SNAPSHOT
 packaging: jar+zip
 inceptionYear: 2011
 
index 3e66d0e5e27d805c26b1348b30e751987d7a5b23..d2fbc52573cd18c71d70827dc83cffc0b7f3032d 100644 (file)
@@ -9,7 +9,8 @@ r26: {
     html: ~
     text: ~
     security: ~
-    fixes: ~
+    fixes:
+    - Reverted change which keyed DataTypeAdapters by the target Java type
     changes: ~
     additions: ~
     dependencyChanges: ~
@@ -30,8 +31,13 @@ r25: {
     fixes:
     - Fix column inheritance from superclasses (pr-14)
     - Use webapp classloader rather than global classloader (pr-12)
+    - Fix deserialization of null values
     changes:
     - Improve SQLite dialect based on upstream JDBC improvements
+    - Key DataTypeAdapters by target Java type
+    - Drop precision and length from SQL->Java type determination
+    - Improve readability of the generated performance benchmark table
+    - Added Derby TCP benchmark test
     additions: ~
     dependencyChanges:
     - SQLite 3.8.10
@@ -56,8 +62,13 @@ r24: {
     fixes:
     - Fix column inheritance from superclasses (pr-14)
     - Use webapp classloader rather than global classloader (pr-12)
+    - Fix deserialization of null values
     changes:
     - Improve SQLite dialect based on upstream JDBC improvements
+    - Key DataTypeAdapters by target Java type
+    - Drop precision and length from SQL->Java type determination
+    - Improve readability of the generated performance benchmark table
+    - Added Derby TCP benchmark test
     additions: ~
     dependencyChanges:
     - SQLite 3.8.10
index deebecafc6ecd2d14d4ebdbe3a9859d0918f9477..34187c4388c28744713f72a9185b366d1bd0eaa0 100644 (file)
@@ -193,18 +193,13 @@ final class DaoProxy<X extends Dao> implements InvocationHandler, Dao {
                } else {
 
                        // query of (array of) standard Java type or a DataTypeAdapter type
-                       if (adapter != null) {
-                               DataTypeAdapter<?> dta = Utils.newObject(adapter);
-                               db.getDialect().registerAdapter(dta);
-                       }
-
                        objects = Utils.newArrayList();
                        ResultSet rs = db.executeQuery(preparedSql.sql, preparedSql.parameters);
                        try {
 
                                while (rs.next()) {
 
-                                       Object value = db.getDialect().deserialize(rs, 1, returnType);
+                                       Object value = db.getDialect().deserialize(rs, 1, returnType, adapter);
                                        objects.add(value);
 
                                        if (!isArray) {
@@ -688,13 +683,8 @@ final class DaoProxy<X extends Dao> implements InvocationHandler, Dao {
                                        typeAdapter = Utils.getDataTypeAdapter(methodArg.getClass().getAnnotations());
                                }
 
-                               if (typeAdapter != null) {
-                                       DataTypeAdapter<?> dta = Utils.newObject(typeAdapter);
-                                       db.getDialect().registerAdapter(dta);
-                               }
-
                                // prepare the parameter
-                               parameters[i] = db.getDialect().serialize(value);
+                               parameters[i] = db.getDialect().serialize(value, typeAdapter);
 
                        }
 
index 1a8cbc7533148a6a4fd139006f6e821d326d7e2c..fd8d0210ffc9d10479904ba4488c3df214bf74e4 100644 (file)
-/*\r
- * Copyright 2004-2011 H2 Group.\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;\r
-\r
-import java.lang.reflect.Field;\r
-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
-\r
-import com.iciql.Iciql.DataTypeAdapter;\r
-import com.iciql.Iciql.EnumType;\r
-import com.iciql.NestedConditions.And;\r
-import com.iciql.NestedConditions.Or;\r
-import com.iciql.bytecode.ClassReader;\r
-import com.iciql.util.IciqlLogger;\r
-import com.iciql.util.JdbcUtils;\r
-import com.iciql.util.Utils;\r
-\r
-/**\r
- * This class represents a query.\r
- *\r
- * @param <T>\r
- *            the return type\r
- */\r
-\r
-public class Query<T> {\r
-\r
-       private Db db;\r
-       private SelectTable<T> from;\r
-       private ArrayList<Token> conditions = Utils.newArrayList();\r
-       private ArrayList<UpdateColumn> updateColumnDeclarations = Utils.newArrayList();\r
-       private int conditionDepth = 0;\r
-       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 ArrayList<Object> groupByExpressions = Utils.newArrayList();\r
-       private long limit;\r
-       private long offset;\r
-\r
-       private Query(Db db) {\r
-               this.db = db;\r
-       }\r
-\r
-       /**\r
-        * from() is a static factory method to build a Query object.\r
-        *\r
-        * @param db\r
-        * @param alias\r
-        * @return a query object\r
-        */\r
-       @SuppressWarnings("unchecked")\r
-       static <T> Query<T> from(Db db, T alias) {\r
-               Query<T> query = new Query<T>(db);\r
-               TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());\r
-               query.from = new SelectTable<T>(db, query, alias, false);\r
-               def.initSelectObject(query.from, alias, query.aliasMap, false);\r
-               return query;\r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-       static <T> Query<T> rebuild(Db db, T alias) {\r
-               Query<T> query = new Query<T>(db);\r
-               TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());\r
-               query.from = new SelectTable<T>(db, query, alias, false);\r
-               def.initSelectObject(query.from, alias, query.aliasMap, true);\r
-               return query;\r
-       }\r
-\r
-       public long selectCount() {\r
-               SQLStatement stat = getSelectStatement(false);\r
-               stat.appendSQL("COUNT(*) ");\r
-               appendFromWhere(stat);\r
-               ResultSet rs = stat.executeQuery();\r
-               try {\r
-                       rs.next();\r
-                       long value = rs.getLong(1);\r
-                       return value;\r
-               } catch (SQLException e) {\r
-                       throw IciqlException.fromSQL(stat.getSQL(), e);\r
-               } finally {\r
-                       JdbcUtils.closeSilently(rs, true);\r
-               }\r
-       }\r
-\r
-       public List<T> select() {\r
-               return select(false);\r
-       }\r
-\r
-       public T selectFirst() {\r
-               List<T> list = limit(1).select(false);\r
-               return list.isEmpty() ? null : list.get(0);\r
-       }\r
-\r
-       public List<T> selectDistinct() {\r
-               return select(true);\r
-       }\r
-\r
-       public <X, Z> X selectFirst(Z x) {\r
-               List<X> list = limit(1).select(x);\r
-               return list.isEmpty() ? null : list.get(0);\r
-       }\r
-\r
-       public <X> void createView(Class<X> viewClass) {\r
-               TableDefinition<X> viewDef = db.define(viewClass);\r
-\r
-               SQLStatement fromWhere = new SQLStatement(db);\r
-               appendFromWhere(fromWhere, false);\r
-\r
-               SQLStatement stat = new SQLStatement(db);\r
-               db.getDialect().prepareCreateView(stat, viewDef, fromWhere.toSQL());\r
-               IciqlLogger.create(stat.toSQL());\r
-               stat.execute();\r
-       }\r
-\r
-       public <X> void replaceView(Class<X> viewClass) {\r
-               db.dropView(viewClass);\r
-               createView(viewClass);\r
-       }\r
-\r
-       public String getSQL() {\r
-               SQLStatement stat = getSelectStatement(false);\r
-               stat.appendSQL("*");\r
-               appendFromWhere(stat);\r
-               return stat.getSQL().trim();\r
-       }\r
-\r
-       /**\r
-        * toSQL returns a static string version of the query with runtime variables\r
-        * properly encoded. This method is also useful when combined with the where\r
-        * clause methods like isParameter() or atLeastParameter() which allows\r
-        * iciql to generate re-usable parameterized string statements.\r
-        *\r
-        * @return the sql query as plain text\r
-        */\r
-       public String toSQL() {\r
-               return toSQL(false);\r
-       }\r
-\r
-       /**\r
-        * toSQL returns a static string version of the query with runtime variables\r
-        * properly encoded. This method is also useful when combined with the where\r
-        * clause methods like isParameter() or atLeastParameter() which allows\r
-        * iciql to generate re-usable parameterized string statements.\r
-        *\r
-        * @param distinct\r
-        *            if true SELECT DISTINCT is used for the query\r
-        * @return the sql query as plain text\r
-        */\r
-       public String toSQL(boolean distinct) {\r
-               return toSQL(distinct, null);\r
-       }\r
-\r
-       /**\r
-        * toSQL returns a static string version of the query with runtime variables\r
-        * properly encoded. This method is also useful when combined with the where\r
-        * clause methods like isParameter() or atLeastParameter() which allows\r
-        * iciql to generate re-usable parameterized string statements.\r
-        *\r
-        * @param distinct\r
-        *            if true SELECT DISTINCT is used for the query\r
-        * @param k\r
-        *            k is used to select only the columns of the specified alias\r
-        *            for an inner join statement. An example of a generated\r
-        *            statement is: SELECT DISTINCT t1.* FROM sometable AS t1 INNER\r
-        *            JOIN othertable AS t2 ON t1.id = t2.id WHERE t2.flag = true\r
-        *            without the alias parameter the statement would start with\r
-        *            SELECT DISTINCT * FROM...\r
-        * @return the sql query as plain text\r
-        */\r
-       public <K> String toSQL(boolean distinct, K k) {\r
-               SQLStatement stat = new SQLStatement(getDb());\r
-               if (updateColumnDeclarations.size() > 0) {\r
-                       stat.appendSQL("UPDATE ");\r
-                       from.appendSQL(stat);\r
-                       stat.appendSQL(" SET ");\r
-                       int i = 0;\r
-                       for (UpdateColumn declaration : updateColumnDeclarations) {\r
-                               if (i++ > 0) {\r
-                                       stat.appendSQL(", ");\r
-                               }\r
-                               declaration.appendSQL(stat);\r
-                       }\r
-                       appendWhere(stat);\r
-               } else {\r
-                       stat.appendSQL("SELECT ");\r
-                       if (distinct) {\r
-                               stat.appendSQL("DISTINCT ");\r
-                       }\r
-                       if (k != null) {\r
-                               SelectTable<?> sel = getSelectTable(k);\r
-                               if (sel == null) {\r
-                                       // unknown alias, use wildcard\r
-                                       IciqlLogger.warn("Alias {0} is not defined in the statement!", k.getClass());\r
-                                       stat.appendSQL("*");\r
-                               } else if (isJoin()) {\r
-                                       // join query, use AS alias\r
-                                       String as = sel.getAs();\r
-                                       stat.appendSQL(as + ".*");\r
-                               } else {\r
-                                       // schema.table.*\r
-                                       String schema = sel.getAliasDefinition().schemaName;\r
-                                       String table = sel.getAliasDefinition().tableName;\r
-                                       String as = getDb().getDialect().prepareTableName(schema, table);\r
-                                       stat.appendSQL(as + ".*");\r
-                               }\r
-                       } else {\r
-                               // alias unspecified, use wildcard\r
-                               stat.appendSQL("*");\r
-                       }\r
-                       appendFromWhere(stat);\r
-               }\r
-               return stat.toSQL().trim();\r
-       }\r
-\r
-       <Z> String toSubQuery(Z z) {\r
-               SQLStatement stat = getSelectStatement(false);\r
-               SelectColumn<T> col = aliasMap.get(z);\r
-               String columnName = col.getFieldDefinition().columnName;\r
-               stat.appendColumn(columnName);\r
-               appendFromWhere(stat);\r
-               return stat.toSQL();\r
-       }\r
-\r
-       private List<T> select(boolean distinct) {\r
-               List<T> result = Utils.newArrayList();\r
-               TableDefinition<T> def = from.getAliasDefinition();\r
-               SQLStatement stat = getSelectStatement(distinct);\r
-               def.appendSelectList(stat);\r
-               appendFromWhere(stat);\r
-               ResultSet rs = stat.executeQuery();\r
-               try {\r
-                       // SQLite returns pre-closed ResultSets for query results with 0 rows\r
-                       if (!rs.isClosed()) {\r
-                               int[] columns = def.mapColumns(false, rs);\r
-                               while (rs.next()) {\r
-                                       T item = from.newObject();\r
-                                       def.readRow(db.getDialect(), item, rs, columns);\r
-                                       result.add(item);\r
-                               }\r
-                       }\r
-               } catch (SQLException e) {\r
-                       throw IciqlException.fromSQL(stat.getSQL(), e);\r
-               } finally {\r
-                       JdbcUtils.closeSilently(rs, true);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       public int delete() {\r
-               SQLStatement stat = new SQLStatement(db);\r
-               stat.appendSQL("DELETE FROM ");\r
-               from.appendSQL(stat);\r
-               appendWhere(stat);\r
-               IciqlLogger.delete(stat.getSQL());\r
-               return stat.executeUpdate();\r
-       }\r
-\r
-       public <A> UpdateColumnSet<T, A> set(A field) {\r
-               from.getAliasDefinition().checkMultipleEnums(field);\r
-               return new UpdateColumnSet<T, A>(this, field);\r
-       }\r
-\r
-       public UpdateColumnSet<T, Boolean> set(boolean field) {\r
-               from.getAliasDefinition().checkMultipleBooleans();\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
-               }\r
-               SQLStatement stat = new SQLStatement(db);\r
-               stat.appendSQL("UPDATE ");\r
-               from.appendSQL(stat);\r
-               stat.appendSQL(" SET ");\r
-               int i = 0;\r
-               for (UpdateColumn declaration : updateColumnDeclarations) {\r
-                       if (i++ > 0) {\r
-                               stat.appendSQL(", ");\r
-                       }\r
-                       declaration.appendSQL(stat);\r
-               }\r
-               appendWhere(stat);\r
-               IciqlLogger.update(stat.getSQL());\r
-               return stat.executeUpdate();\r
-       }\r
-\r
-       public <X, Z> List<X> selectDistinct(Z x) {\r
-               return select(x, true);\r
-       }\r
-\r
-       public <X, Z> List<X> select(Z x) {\r
-               return select(x, false);\r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-       private <X, Z> List<X> select(Z x, boolean distinct) {\r
-               Class<?> clazz = x.getClass();\r
-               if (Utils.isSimpleType(clazz)) {\r
-                       return selectSimple((X) x, distinct);\r
-               }\r
-               Class<?> enclosingClass = clazz.getEnclosingClass();\r
-               if (enclosingClass != null) {\r
-                       // anonymous inner class\r
-                       clazz = clazz.getSuperclass();\r
-               }\r
-               return select((Class<X>) clazz, (X) x, distinct);\r
-       }\r
-\r
-       private <X> List<X> select(Class<X> clazz, X x, boolean distinct) {\r
-               List<X> result = Utils.newArrayList();\r
-               TableDefinition<X> def = db.define(clazz);\r
-               SQLStatement stat = getSelectStatement(distinct);\r
-               def.appendSelectList(stat, this, x);\r
-               appendFromWhere(stat);\r
-               ResultSet rs = stat.executeQuery();\r
-               try {\r
-                       // SQLite returns pre-closed ResultSets for query results with 0 rows\r
-                       if (!rs.isClosed()) {\r
-                               int[] columns = def.mapColumns(false, rs);\r
-                               while (rs.next()) {\r
-                                       X row = Utils.newObject(clazz);\r
-                                       def.readRow(db.getDialect(), row, rs, columns);\r
-                                       result.add(row);\r
-                               }\r
-                       }\r
-               } catch (SQLException e) {\r
-                       throw IciqlException.fromSQL(stat.getSQL(), e);\r
-               } finally {\r
-                       JdbcUtils.closeSilently(rs, true);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       @SuppressWarnings("unchecked")\r
-       private <X> List<X> selectSimple(X x, boolean distinct) {\r
-               SQLStatement stat = getSelectStatement(distinct);\r
-               appendSQL(stat, null, x);\r
-               appendFromWhere(stat);\r
-               ResultSet rs = stat.executeQuery();\r
-               List<X> result = Utils.newArrayList();\r
-               Class<? extends DataTypeAdapter<?>> typeAdapter = Utils.getDataTypeAdapter(x.getClass().getAnnotations());\r
-               if (typeAdapter != null) {\r
-                       DataTypeAdapter<?> dta = Utils.newObject(typeAdapter);\r
-                       db.getDialect().registerAdapter(dta);\r
-               }\r
-               try {\r
-                       // SQLite returns pre-closed ResultSets for query results with 0 rows\r
-                       if (!rs.isClosed()) {\r
-                               while (rs.next()) {\r
-                                       X value = (X) db.getDialect().deserialize(rs, 1, x.getClass());\r
-                                       result.add(value);\r
-                               }\r
-                       }\r
-               } catch (Exception e) {\r
-                       throw IciqlException.fromSQL(stat.getSQL(), e);\r
-               } finally {\r
-                       JdbcUtils.closeSilently(rs, true);\r
-               }\r
-               return result;\r
-       }\r
-\r
-       private SQLStatement getSelectStatement(boolean distinct) {\r
-               SQLStatement stat = new SQLStatement(db);\r
-               stat.appendSQL("SELECT ");\r
-               if (distinct) {\r
-                       stat.appendSQL("DISTINCT ");\r
-               }\r
-               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
-               from.getAliasDefinition().checkMultipleBooleans();\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
-               from.getAliasDefinition().checkMultipleEnums(x);\r
-               return new QueryCondition<T, A>(this, x);\r
-       }\r
-\r
-       public <A> QueryWhere<T> where(Filter filter) {\r
-               HashMap<String, Object> fieldMap = Utils.newHashMap();\r
-               for (Field f : filter.getClass().getDeclaredFields()) {\r
-                       f.setAccessible(true);\r
-                       try {\r
-                               Object obj = f.get(filter);\r
-                               if (obj == from.getAlias()) {\r
-                                       List<TableDefinition.FieldDefinition> fields = from.getAliasDefinition().getFields();\r
-                                       String name = f.getName();\r
-                                       for (TableDefinition.FieldDefinition field : fields) {\r
-                                               String n = name + "." + field.field.getName();\r
-                                               Object o = field.field.get(obj);\r
-                                               fieldMap.put(n, o);\r
-                                       }\r
-                               }\r
-                               fieldMap.put(f.getName(), f.get(filter));\r
-                       } catch (Exception e) {\r
-                               throw new IciqlException(e);\r
-                       }\r
-               }\r
-               Token filterCode = new ClassReader().decompile(filter, fieldMap, "where");\r
-               // String filterQuery = filterCode.toString();\r
-               conditions.add(filterCode);\r
-               return new QueryWhere<T>(this);\r
-       }\r
-\r
-       public QueryWhere<T> where(String fragment, List<?> args) {\r
-               return this.where(fragment, args.toArray());\r
-       }\r
-\r
-       public QueryWhere<T> where(String fragment, Object... args) {\r
-               conditions.add(new RuntimeToken(fragment, args));\r
-               return new QueryWhere<T>(this);\r
-       }\r
-\r
-       public Query<T> where(And<T> conditions) {\r
-               whereTrue();\r
-               addConditionToken(conditions.where.query);\r
-               return this;\r
-       }\r
-\r
-       public Query<T> where(Or<T> conditions) {\r
-               whereFalse();\r
-               addConditionToken(conditions.where.query);\r
-               return this;\r
-       }\r
-\r
-       public QueryWhere<T> whereTrue() {\r
-               return whereTrue(true);\r
-       }\r
-\r
-       public QueryWhere<T> whereFalse() {\r
-               return whereTrue(false);\r
-       }\r
-\r
-       public QueryWhere<T> whereTrue(Boolean condition) {\r
-               Token token = new Function("", condition);\r
-               addConditionToken(token);\r
-               return new QueryWhere<T>(this);\r
-       }\r
-\r
-       /**\r
-        * Sets the Limit and Offset of a query.\r
-        *\r
-        * @return the query\r
-        */\r
-\r
-       public Query<T> limit(long limit) {\r
-               this.limit = limit;\r
-               return this;\r
-       }\r
-\r
-       public Query<T> offset(long offset) {\r
-               this.offset = offset;\r
-               return this;\r
-       }\r
-\r
-       public Query<T> orderBy(boolean field) {\r
-               from.getAliasDefinition().checkMultipleBooleans();\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
-               from.getAliasDefinition().checkMultipleEnums(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
-        * @param expressions\r
-        *            the columns\r
-        * @return the query\r
-        */\r
-\r
-       public Query<T> orderBy(Object... expressions) {\r
-               for (Object expr : expressions) {\r
-                       from.getAliasDefinition().checkMultipleEnums(expr);\r
-                       OrderExpression<T> e = new OrderExpression<T>(this, expr, false, false, false);\r
-                       addOrderBy(e);\r
-               }\r
-               return this;\r
-       }\r
-\r
-       public Query<T> orderByDesc(Object expr) {\r
-               OrderExpression<T> e = new OrderExpression<T>(this, expr, true, false, false);\r
-               addOrderBy(e);\r
-               return this;\r
-       }\r
-\r
-       public Query<T> groupBy(boolean field) {\r
-               from.getAliasDefinition().checkMultipleBooleans();\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(byte field) {\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(short field) {\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(int field) {\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(long field) {\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(float field) {\r
-               return groupByPrimitive(field);\r
-       }\r
-\r
-       public Query<T> groupBy(double field) {\r
-               return groupByPrimitive(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
-               from.getAliasDefinition().checkMultipleEnums(expr);\r
-               groupByExpressions.add(expr);\r
-               return this;\r
-       }\r
-\r
-       public Query<T> groupBy(Object... groupBy) {\r
-               this.groupByExpressions.addAll(Arrays.asList(groupBy));\r
-               return this;\r
-       }\r
-\r
-       /**\r
-        * INTERNAL\r
-        *\r
-        * @param stat\r
-        *            the statement\r
-        * @param alias\r
-        *            the alias object (can be null)\r
-        * @param value\r
-        *            the value\r
-        */\r
-       public void appendSQL(SQLStatement stat, Object alias, Object value) {\r
-               if (Function.count() == value) {\r
-                       stat.appendSQL("COUNT(*)");\r
-                       return;\r
-               }\r
-               if (RuntimeParameter.PARAMETER == value) {\r
-                       stat.appendSQL("?");\r
-                       addParameter(stat, alias, value);\r
-                       return;\r
-               }\r
-               Token token = Db.getToken(value);\r
-               if (token != null) {\r
-                       token.appendSQL(stat, this);\r
-                       return;\r
-               }\r
-               if (alias != null && value.getClass().isEnum()) {\r
-                       // special case:\r
-                       // value is first enum constant which is also the alias object.\r
-                       // the first enum constant is used as the alias because we can not\r
-                       // instantiate an enum reflectively.\r
-                       stat.appendSQL("?");\r
-                       addParameter(stat, alias, value);\r
-                       return;\r
-               }\r
-               SelectColumn<T> col = getColumnByReference(value);\r
-               if (col != null) {\r
-                       col.appendSQL(stat);\r
-                       return;\r
-               }\r
-               stat.appendSQL("?");\r
-               addParameter(stat, alias, value);\r
-       }\r
-\r
-       /**\r
-        * INTERNAL\r
-        *\r
-        * @param stat\r
-        *            the statement\r
-        * @param alias\r
-        *            the alias object (can be null)\r
-        * @param valueLeft\r
-        *            the value on the left of the compound clause\r
-        * @param valueRight\r
-        *            the value on the right of the compound clause\r
-        * @param compareType\r
-        *            the current compare type (e.g. BETWEEN)\r
-        */\r
-       public void appendSQL(SQLStatement stat, Object alias, Object valueLeft, Object valueRight,\r
-                       CompareType compareType) {\r
-               stat.appendSQL("?");\r
-               stat.appendSQL(" ");\r
-               switch (compareType) {\r
-               case BETWEEN:\r
-                       stat.appendSQL("AND");\r
-                       break;\r
-               }\r
-               stat.appendSQL(" ");\r
-               stat.appendSQL("?");\r
-               addParameter(stat, alias, valueLeft);\r
-               addParameter(stat, alias, valueRight);\r
-       }\r
-\r
-       public void appendSQL(SQLStatement stat, Object alias, Iterable<Object> values,\r
-                       CompareType compareType) {\r
-               boolean first = true;\r
-               stat.appendSQL("(");\r
-               for (Object value : values) {\r
-                       if (first) {\r
-                               first = false;\r
-                       } else {\r
-                               stat.appendSQL(", ");\r
-                       }\r
-                       stat.appendSQL("?");\r
-                       addParameter(stat, alias, value);\r
-               }\r
-               stat.appendSQL(")");\r
-       }\r
-\r
-       private void addParameter(SQLStatement stat, Object alias, Object value) {\r
-               SelectColumn<T> col = getColumnByReference(alias);\r
-               if (col != null && value.getClass().isEnum()) {\r
-                       // enum\r
-                       EnumType type = col.getFieldDefinition().enumType;\r
-                       Enum<?> anEnum = (Enum<?>) value;\r
-                       Object y = Utils.convertEnum(anEnum, type);\r
-                       stat.addParameter(y);\r
-               } else if (col != null) {\r
-                       // object\r
-                       Object parameter = db.getDialect().serialize(value);\r
-                       stat.addParameter(parameter);\r
-               } else {\r
-                       // primitive\r
-                       stat.addParameter(value);\r
-               }\r
-       }\r
-\r
-       void addConditionToken(Token condition) {\r
-               if (condition == ConditionOpenClose.OPEN) {\r
-                       conditionDepth ++;\r
-               } else if (condition == ConditionOpenClose.CLOSE) {\r
-                       conditionDepth --;\r
-                       if (conditionDepth < 0) {\r
-                               throw new IciqlException("unmatch condition open-close count");\r
-                       }\r
-               }\r
-               conditions.add(condition);\r
-       }\r
-\r
-       void addConditionToken(Query<T> other) {\r
-               for (Token condition : other.conditions) {\r
-                       addConditionToken(condition);\r
-               }\r
-       }\r
-\r
-       void addUpdateColumnDeclaration(UpdateColumn declaration) {\r
-               updateColumnDeclarations.add(declaration);\r
-       }\r
-\r
-       void appendWhere(SQLStatement stat) {\r
-               if (conditionDepth != 0) {\r
-                       throw new IciqlException("unmatch condition open-close count");\r
-               }\r
-               if (!conditions.isEmpty()) {\r
-                       stat.appendSQL(" WHERE ");\r
-\r
-                       boolean skipNextConjunction = false;\r
-\r
-                       for (Token token : conditions) {\r
-\r
-                               if (skipNextConjunction && token instanceof ConditionAndOr) {\r
-                                       skipNextConjunction = false;\r
-                                       continue;\r
-                               }\r
-\r
-                               token.appendSQL(stat, this);\r
-                               stat.appendSQL(" ");\r
-\r
-                               if (ConditionOpenClose.OPEN == token) {\r
-                                       skipNextConjunction = true;\r
-                               }\r
-                       }\r
-               }\r
-       }\r
-\r
-       void appendFromWhere(SQLStatement stat) {\r
-               appendFromWhere(stat, true);\r
-       }\r
-\r
-       void appendFromWhere(SQLStatement stat, boolean log) {\r
-               stat.appendSQL(" FROM ");\r
-               from.appendSQL(stat);\r
-               for (SelectTable<T> join : joins) {\r
-                       join.appendSQLAsJoin(stat, this);\r
-               }\r
-               appendWhere(stat);\r
-               if (!groupByExpressions.isEmpty()) {\r
-                       stat.appendSQL(" GROUP BY ");\r
-                       int i = 0;\r
-                       for (Object obj : groupByExpressions) {\r
-                               if (i++ > 0) {\r
-                                       stat.appendSQL(", ");\r
-                               }\r
-                               appendSQL(stat, null, obj);\r
-                               stat.appendSQL(" ");\r
-                       }\r
-               }\r
-               if (!orderByList.isEmpty()) {\r
-                       stat.appendSQL(" ORDER BY ");\r
-                       int i = 0;\r
-                       for (OrderExpression<T> o : orderByList) {\r
-                               if (i++ > 0) {\r
-                                       stat.appendSQL(", ");\r
-                               }\r
-                               o.appendSQL(stat);\r
-                               stat.appendSQL(" ");\r
-                       }\r
-               }\r
-               db.getDialect().appendLimitOffset(stat, limit, offset);\r
-               if (log) {\r
-                       IciqlLogger.select(stat.getSQL());\r
-               }\r
-       }\r
-\r
-       /**\r
-        * Join another table.\r
-        *\r
-        * @param alias\r
-        *            an alias for the table to join\r
-        * @return the joined query\r
-        */\r
-\r
-       public <A> QueryJoin<T> innerJoin(A alias) {\r
-        return join(alias, false);\r
-       }\r
-\r
-    public <A> QueryJoin<T> leftJoin(A alias) {\r
-        return join(alias, true);\r
-    }\r
-\r
-    @SuppressWarnings({ "unchecked", "rawtypes" })\r
-    private <A> QueryJoin<T> join(A alias, boolean outerJoin) {\r
-        TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());\r
-        SelectTable<T> join = new SelectTable(db, this, alias, outerJoin);\r
-        def.initSelectObject(join, alias, aliasMap, false);\r
-        joins.add(join);\r
-        return new QueryJoin(this, join);\r
-    }\r
-\r
-       Db getDb() {\r
-               return db;\r
-       }\r
-\r
-       SelectTable<T> getFrom() {\r
-               return from;\r
-       }\r
-\r
-       boolean isJoin() {\r
-               return !joins.isEmpty();\r
-       }\r
-\r
-       SelectTable<?> getSelectTable(Object alias) {\r
-               if (from.getAlias() == alias) {\r
-                       return from;\r
-               } else {\r
-                       for (SelectTable<?> join : joins) {\r
-                               if (join.getAlias() == alias) {\r
-                                       return join;\r
-                               }\r
-                       }\r
-               }\r
-               return null;\r
-       }\r
-\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
-               orderByList.add(expr);\r
-       }\r
-\r
-}\r
+/*
+ * Copyright 2004-2011 H2 Group.
+ * Copyright 2011 James Moger.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iciql;
+
+import java.lang.reflect.Field;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+
+import com.iciql.Iciql.DataTypeAdapter;
+import com.iciql.Iciql.EnumType;
+import com.iciql.NestedConditions.And;
+import com.iciql.NestedConditions.Or;
+import com.iciql.bytecode.ClassReader;
+import com.iciql.util.IciqlLogger;
+import com.iciql.util.JdbcUtils;
+import com.iciql.util.Utils;
+
+/**
+ * This class represents a query.
+ *
+ * @param <T>
+ *            the return type
+ */
+
+public class Query<T> {
+
+       private Db db;
+       private SelectTable<T> from;
+       private ArrayList<Token> conditions = Utils.newArrayList();
+       private ArrayList<UpdateColumn> updateColumnDeclarations = Utils.newArrayList();
+       private int conditionDepth = 0;
+       private ArrayList<SelectTable<T>> joins = Utils.newArrayList();
+       private final IdentityHashMap<Object, SelectColumn<T>> aliasMap = Utils.newIdentityHashMap();
+       private ArrayList<OrderExpression<T>> orderByList = Utils.newArrayList();
+       private ArrayList<Object> groupByExpressions = Utils.newArrayList();
+       private long limit;
+       private long offset;
+
+       private Query(Db db) {
+               this.db = db;
+       }
+
+       /**
+        * from() is a static factory method to build a Query object.
+        *
+        * @param db
+        * @param alias
+        * @return a query object
+        */
+       @SuppressWarnings("unchecked")
+       static <T> Query<T> from(Db db, T alias) {
+               Query<T> query = new Query<T>(db);
+               TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());
+               query.from = new SelectTable<T>(db, query, alias, false);
+               def.initSelectObject(query.from, alias, query.aliasMap, false);
+               return query;
+       }
+
+       @SuppressWarnings("unchecked")
+       static <T> Query<T> rebuild(Db db, T alias) {
+               Query<T> query = new Query<T>(db);
+               TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());
+               query.from = new SelectTable<T>(db, query, alias, false);
+               def.initSelectObject(query.from, alias, query.aliasMap, true);
+               return query;
+       }
+
+       public long selectCount() {
+               SQLStatement stat = getSelectStatement(false);
+               stat.appendSQL("COUNT(*) ");
+               appendFromWhere(stat);
+               ResultSet rs = stat.executeQuery();
+               try {
+                       rs.next();
+                       long value = rs.getLong(1);
+                       return value;
+               } catch (SQLException e) {
+                       throw IciqlException.fromSQL(stat.getSQL(), e);
+               } finally {
+                       JdbcUtils.closeSilently(rs, true);
+               }
+       }
+
+       public List<T> select() {
+               return select(false);
+       }
+
+       public T selectFirst() {
+               List<T> list = limit(1).select(false);
+               return list.isEmpty() ? null : list.get(0);
+       }
+
+       public List<T> selectDistinct() {
+               return select(true);
+       }
+
+       public <X, Z> X selectFirst(Z x) {
+               List<X> list = limit(1).select(x);
+               return list.isEmpty() ? null : list.get(0);
+       }
+
+       public <X> void createView(Class<X> viewClass) {
+               TableDefinition<X> viewDef = db.define(viewClass);
+
+               SQLStatement fromWhere = new SQLStatement(db);
+               appendFromWhere(fromWhere, false);
+
+               SQLStatement stat = new SQLStatement(db);
+               db.getDialect().prepareCreateView(stat, viewDef, fromWhere.toSQL());
+               IciqlLogger.create(stat.toSQL());
+               stat.execute();
+       }
+
+       public <X> void replaceView(Class<X> viewClass) {
+               db.dropView(viewClass);
+               createView(viewClass);
+       }
+
+       public String getSQL() {
+               SQLStatement stat = getSelectStatement(false);
+               stat.appendSQL("*");
+               appendFromWhere(stat);
+               return stat.getSQL().trim();
+       }
+
+       /**
+        * toSQL returns a static string version of the query with runtime variables
+        * properly encoded. This method is also useful when combined with the where
+        * clause methods like isParameter() or atLeastParameter() which allows
+        * iciql to generate re-usable parameterized string statements.
+        *
+        * @return the sql query as plain text
+        */
+       public String toSQL() {
+               return toSQL(false);
+       }
+
+       /**
+        * toSQL returns a static string version of the query with runtime variables
+        * properly encoded. This method is also useful when combined with the where
+        * clause methods like isParameter() or atLeastParameter() which allows
+        * iciql to generate re-usable parameterized string statements.
+        *
+        * @param distinct
+        *            if true SELECT DISTINCT is used for the query
+        * @return the sql query as plain text
+        */
+       public String toSQL(boolean distinct) {
+               return toSQL(distinct, null);
+       }
+
+       /**
+        * toSQL returns a static string version of the query with runtime variables
+        * properly encoded. This method is also useful when combined with the where
+        * clause methods like isParameter() or atLeastParameter() which allows
+        * iciql to generate re-usable parameterized string statements.
+        *
+        * @param distinct
+        *            if true SELECT DISTINCT is used for the query
+        * @param k
+        *            k is used to select only the columns of the specified alias
+        *            for an inner join statement. An example of a generated
+        *            statement is: SELECT DISTINCT t1.* FROM sometable AS t1 INNER
+        *            JOIN othertable AS t2 ON t1.id = t2.id WHERE t2.flag = true
+        *            without the alias parameter the statement would start with
+        *            SELECT DISTINCT * FROM...
+        * @return the sql query as plain text
+        */
+       public <K> String toSQL(boolean distinct, K k) {
+               SQLStatement stat = new SQLStatement(getDb());
+               if (updateColumnDeclarations.size() > 0) {
+                       stat.appendSQL("UPDATE ");
+                       from.appendSQL(stat);
+                       stat.appendSQL(" SET ");
+                       int i = 0;
+                       for (UpdateColumn declaration : updateColumnDeclarations) {
+                               if (i++ > 0) {
+                                       stat.appendSQL(", ");
+                               }
+                               declaration.appendSQL(stat);
+                       }
+                       appendWhere(stat);
+               } else {
+                       stat.appendSQL("SELECT ");
+                       if (distinct) {
+                               stat.appendSQL("DISTINCT ");
+                       }
+                       if (k != null) {
+                               SelectTable<?> sel = getSelectTable(k);
+                               if (sel == null) {
+                                       // unknown alias, use wildcard
+                                       IciqlLogger.warn("Alias {0} is not defined in the statement!", k.getClass());
+                                       stat.appendSQL("*");
+                               } else if (isJoin()) {
+                                       // join query, use AS alias
+                                       String as = sel.getAs();
+                                       stat.appendSQL(as + ".*");
+                               } else {
+                                       // schema.table.*
+                                       String schema = sel.getAliasDefinition().schemaName;
+                                       String table = sel.getAliasDefinition().tableName;
+                                       String as = getDb().getDialect().prepareTableName(schema, table);
+                                       stat.appendSQL(as + ".*");
+                               }
+                       } else {
+                               // alias unspecified, use wildcard
+                               stat.appendSQL("*");
+                       }
+                       appendFromWhere(stat);
+               }
+               return stat.toSQL().trim();
+       }
+
+       <Z> String toSubQuery(Z z) {
+               SQLStatement stat = getSelectStatement(false);
+               SelectColumn<T> col = aliasMap.get(z);
+               String columnName = col.getFieldDefinition().columnName;
+               stat.appendColumn(columnName);
+               appendFromWhere(stat);
+               return stat.toSQL();
+       }
+
+       private List<T> select(boolean distinct) {
+               List<T> result = Utils.newArrayList();
+               TableDefinition<T> def = from.getAliasDefinition();
+               SQLStatement stat = getSelectStatement(distinct);
+               def.appendSelectList(stat);
+               appendFromWhere(stat);
+               ResultSet rs = stat.executeQuery();
+               try {
+                       // SQLite returns pre-closed ResultSets for query results with 0 rows
+                       if (!rs.isClosed()) {
+                               int[] columns = def.mapColumns(false, rs);
+                               while (rs.next()) {
+                                       T item = from.newObject();
+                                       def.readRow(db.getDialect(), item, rs, columns);
+                                       result.add(item);
+                               }
+                       }
+               } catch (SQLException e) {
+                       throw IciqlException.fromSQL(stat.getSQL(), e);
+               } finally {
+                       JdbcUtils.closeSilently(rs, true);
+               }
+               return result;
+       }
+
+       public int delete() {
+               SQLStatement stat = new SQLStatement(db);
+               stat.appendSQL("DELETE FROM ");
+               from.appendSQL(stat);
+               appendWhere(stat);
+               IciqlLogger.delete(stat.getSQL());
+               return stat.executeUpdate();
+       }
+
+       public <A> UpdateColumnSet<T, A> set(A field) {
+               from.getAliasDefinition().checkMultipleEnums(field);
+               return new UpdateColumnSet<T, A>(this, field);
+       }
+
+       public UpdateColumnSet<T, Boolean> set(boolean field) {
+               from.getAliasDefinition().checkMultipleBooleans();
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Byte> set(byte field) {
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Short> set(short field) {
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Integer> set(int field) {
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Long> set(long field) {
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Float> set(float field) {
+               return setPrimitive(field);
+       }
+
+       public UpdateColumnSet<T, Double> set(double field) {
+               return setPrimitive(field);
+       }
+
+       private <A> UpdateColumnSet<T, A> setPrimitive(A field) {
+               A alias = getPrimitiveAliasByValue(field);
+               if (alias == null) {
+                       // this will result in an unmapped field exception
+                       return set(field);
+               }
+               return set(alias);
+       }
+
+       public <A> UpdateColumnIncrement<T, A> increment(A field) {
+               return new UpdateColumnIncrement<T, A>(this, field);
+       }
+
+       public UpdateColumnIncrement<T, Byte> increment(byte field) {
+               return incrementPrimitive(field);
+       }
+
+       public UpdateColumnIncrement<T, Short> increment(short field) {
+               return incrementPrimitive(field);
+       }
+
+       public UpdateColumnIncrement<T, Integer> increment(int field) {
+               return incrementPrimitive(field);
+       }
+
+       public UpdateColumnIncrement<T, Long> increment(long field) {
+               return incrementPrimitive(field);
+       }
+
+       public UpdateColumnIncrement<T, Float> increment(float field) {
+               return incrementPrimitive(field);
+       }
+
+       public UpdateColumnIncrement<T, Double> increment(double field) {
+               return incrementPrimitive(field);
+       }
+
+       private <A> UpdateColumnIncrement<T, A> incrementPrimitive(A field) {
+               A alias = getPrimitiveAliasByValue(field);
+               if (alias == null) {
+                       // this will result in an unmapped field exception
+                       return increment(field);
+               }
+               return increment(alias);
+       }
+
+       public int update() {
+               if (updateColumnDeclarations.size() == 0) {
+                       throw new IciqlException("Missing set or increment call.");
+               }
+               SQLStatement stat = new SQLStatement(db);
+               stat.appendSQL("UPDATE ");
+               from.appendSQL(stat);
+               stat.appendSQL(" SET ");
+               int i = 0;
+               for (UpdateColumn declaration : updateColumnDeclarations) {
+                       if (i++ > 0) {
+                               stat.appendSQL(", ");
+                       }
+                       declaration.appendSQL(stat);
+               }
+               appendWhere(stat);
+               IciqlLogger.update(stat.getSQL());
+               return stat.executeUpdate();
+       }
+
+       public <X, Z> List<X> selectDistinct(Z x) {
+               return select(x, true);
+       }
+
+       public <X, Z> List<X> select(Z x) {
+               return select(x, false);
+       }
+
+       @SuppressWarnings("unchecked")
+       private <X, Z> List<X> select(Z x, boolean distinct) {
+               Class<?> clazz = x.getClass();
+               if (Utils.isSimpleType(clazz)) {
+                       return selectSimple((X) x, distinct);
+               }
+               Class<?> enclosingClass = clazz.getEnclosingClass();
+               if (enclosingClass != null) {
+                       // anonymous inner class
+                       clazz = clazz.getSuperclass();
+               }
+               return select((Class<X>) clazz, (X) x, distinct);
+       }
+
+       private <X> List<X> select(Class<X> clazz, X x, boolean distinct) {
+               List<X> result = Utils.newArrayList();
+               TableDefinition<X> def = db.define(clazz);
+               SQLStatement stat = getSelectStatement(distinct);
+               def.appendSelectList(stat, this, x);
+               appendFromWhere(stat);
+               ResultSet rs = stat.executeQuery();
+               try {
+                       // SQLite returns pre-closed ResultSets for query results with 0 rows
+                       if (!rs.isClosed()) {
+                               int[] columns = def.mapColumns(false, rs);
+                               while (rs.next()) {
+                                       X row = Utils.newObject(clazz);
+                                       def.readRow(db.getDialect(), row, rs, columns);
+                                       result.add(row);
+                               }
+                       }
+               } catch (SQLException e) {
+                       throw IciqlException.fromSQL(stat.getSQL(), e);
+               } finally {
+                       JdbcUtils.closeSilently(rs, true);
+               }
+               return result;
+       }
+
+       @SuppressWarnings("unchecked")
+       private <X> List<X> selectSimple(X x, boolean distinct) {
+               SQLStatement stat = getSelectStatement(distinct);
+               appendSQL(stat, null, x);
+               appendFromWhere(stat);
+               ResultSet rs = stat.executeQuery();
+               List<X> result = Utils.newArrayList();
+               Class<? extends DataTypeAdapter<?>> typeAdapter = Utils.getDataTypeAdapter(x.getClass().getAnnotations());
+               try {
+                       // SQLite returns pre-closed ResultSets for query results with 0 rows
+                       if (!rs.isClosed()) {
+                               while (rs.next()) {
+                                       X value = (X) db.getDialect().deserialize(rs, 1, x.getClass(), typeAdapter);
+                                       result.add(value);
+                               }
+                       }
+               } catch (Exception e) {
+                       throw IciqlException.fromSQL(stat.getSQL(), e);
+               } finally {
+                       JdbcUtils.closeSilently(rs, true);
+               }
+               return result;
+       }
+
+       private SQLStatement getSelectStatement(boolean distinct) {
+               SQLStatement stat = new SQLStatement(db);
+               stat.appendSQL("SELECT ");
+               if (distinct) {
+                       stat.appendSQL("DISTINCT ");
+               }
+               return stat;
+       }
+
+       /**
+        * Begin a primitive boolean field condition clause.
+        *
+        * @param x
+        *            the primitive boolean field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Boolean> where(boolean x) {
+               from.getAliasDefinition().checkMultipleBooleans();
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive short field condition clause.
+        *
+        * @param x
+        *            the primitive short field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Byte> where(byte x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive short field condition clause.
+        *
+        * @param x
+        *            the primitive short field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Short> where(short x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive int field condition clause.
+        *
+        * @param x
+        *            the primitive int field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Integer> where(int x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive long field condition clause.
+        *
+        * @param x
+        *            the primitive long field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Long> where(long x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive float field condition clause.
+        *
+        * @param x
+        *            the primitive float field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Float> where(float x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begin a primitive double field condition clause.
+        *
+        * @param x
+        *            the primitive double field to query
+        * @return a query condition to continue building the condition
+        */
+       public QueryCondition<T, Double> where(double x) {
+               return wherePrimitive(x);
+       }
+
+       /**
+        * Begins a primitive field condition clause.
+        *
+        * @param value
+        * @return a query condition to continue building the condition
+        */
+       private <A> QueryCondition<T, A> wherePrimitive(A value) {
+               A alias = getPrimitiveAliasByValue(value);
+               if (alias == null) {
+                       // this will result in an unmapped field exception
+                       return where(value);
+               }
+               return where(alias);
+       }
+
+       /**
+        * Begin an Object field condition clause.
+        *
+        * @param x
+        *            the mapped object to query
+        * @return a query condition to continue building the condition
+        */
+       public <A> QueryCondition<T, A> where(A x) {
+               from.getAliasDefinition().checkMultipleEnums(x);
+               return new QueryCondition<T, A>(this, x);
+       }
+
+       public <A> QueryWhere<T> where(Filter filter) {
+               HashMap<String, Object> fieldMap = Utils.newHashMap();
+               for (Field f : filter.getClass().getDeclaredFields()) {
+                       f.setAccessible(true);
+                       try {
+                               Object obj = f.get(filter);
+                               if (obj == from.getAlias()) {
+                                       List<TableDefinition.FieldDefinition> fields = from.getAliasDefinition().getFields();
+                                       String name = f.getName();
+                                       for (TableDefinition.FieldDefinition field : fields) {
+                                               String n = name + "." + field.field.getName();
+                                               Object o = field.field.get(obj);
+                                               fieldMap.put(n, o);
+                                       }
+                               }
+                               fieldMap.put(f.getName(), f.get(filter));
+                       } catch (Exception e) {
+                               throw new IciqlException(e);
+                       }
+               }
+               Token filterCode = new ClassReader().decompile(filter, fieldMap, "where");
+               // String filterQuery = filterCode.toString();
+               conditions.add(filterCode);
+               return new QueryWhere<T>(this);
+       }
+
+       public QueryWhere<T> where(String fragment, List<?> args) {
+               return this.where(fragment, args.toArray());
+       }
+
+       public QueryWhere<T> where(String fragment, Object... args) {
+               conditions.add(new RuntimeToken(fragment, args));
+               return new QueryWhere<T>(this);
+       }
+
+       public Query<T> where(And<T> conditions) {
+               whereTrue();
+               addConditionToken(conditions.where.query);
+               return this;
+       }
+
+       public Query<T> where(Or<T> conditions) {
+               whereFalse();
+               addConditionToken(conditions.where.query);
+               return this;
+       }
+
+       public QueryWhere<T> whereTrue() {
+               return whereTrue(true);
+       }
+
+       public QueryWhere<T> whereFalse() {
+               return whereTrue(false);
+       }
+
+       public QueryWhere<T> whereTrue(Boolean condition) {
+               Token token = new Function("", condition);
+               addConditionToken(token);
+               return new QueryWhere<T>(this);
+       }
+
+       /**
+        * Sets the Limit and Offset of a query.
+        *
+        * @return the query
+        */
+
+       public Query<T> limit(long limit) {
+               this.limit = limit;
+               return this;
+       }
+
+       public Query<T> offset(long offset) {
+               this.offset = offset;
+               return this;
+       }
+
+       public Query<T> orderBy(boolean field) {
+               from.getAliasDefinition().checkMultipleBooleans();
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(byte field) {
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(short field) {
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(int field) {
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(long field) {
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(float field) {
+               return orderByPrimitive(field);
+       }
+
+       public Query<T> orderBy(double field) {
+               return orderByPrimitive(field);
+       }
+
+       Query<T> orderByPrimitive(Object field) {
+               Object alias = getPrimitiveAliasByValue(field);
+               if (alias == null) {
+                       return orderBy(field);
+               }
+               return orderBy(alias);
+       }
+
+       public Query<T> orderBy(Object expr) {
+               from.getAliasDefinition().checkMultipleEnums(expr);
+               OrderExpression<T> e = new OrderExpression<T>(this, expr, false, false, false);
+               addOrderBy(e);
+               return this;
+       }
+
+       /**
+        * Order by a number of columns.
+        *
+        * @param expressions
+        *            the columns
+        * @return the query
+        */
+
+       public Query<T> orderBy(Object... expressions) {
+               for (Object expr : expressions) {
+                       from.getAliasDefinition().checkMultipleEnums(expr);
+                       OrderExpression<T> e = new OrderExpression<T>(this, expr, false, false, false);
+                       addOrderBy(e);
+               }
+               return this;
+       }
+
+       public Query<T> orderByDesc(Object expr) {
+               OrderExpression<T> e = new OrderExpression<T>(this, expr, true, false, false);
+               addOrderBy(e);
+               return this;
+       }
+
+       public Query<T> groupBy(boolean field) {
+               from.getAliasDefinition().checkMultipleBooleans();
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(byte field) {
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(short field) {
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(int field) {
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(long field) {
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(float field) {
+               return groupByPrimitive(field);
+       }
+
+       public Query<T> groupBy(double field) {
+               return groupByPrimitive(field);
+       }
+
+       Query<T> groupByPrimitive(Object field) {
+               Object alias = getPrimitiveAliasByValue(field);
+               if (alias == null) {
+                       return groupBy(field);
+               }
+               return groupBy(alias);
+       }
+
+       public Query<T> groupBy(Object expr) {
+               from.getAliasDefinition().checkMultipleEnums(expr);
+               groupByExpressions.add(expr);
+               return this;
+       }
+
+       public Query<T> groupBy(Object... groupBy) {
+               this.groupByExpressions.addAll(Arrays.asList(groupBy));
+               return this;
+       }
+
+       /**
+        * INTERNAL
+        *
+        * @param stat
+        *            the statement
+        * @param alias
+        *            the alias object (can be null)
+        * @param value
+        *            the value
+        */
+       public void appendSQL(SQLStatement stat, Object alias, Object value) {
+               if (Function.count() == value) {
+                       stat.appendSQL("COUNT(*)");
+                       return;
+               }
+               if (RuntimeParameter.PARAMETER == value) {
+                       stat.appendSQL("?");
+                       addParameter(stat, alias, value);
+                       return;
+               }
+               Token token = Db.getToken(value);
+               if (token != null) {
+                       token.appendSQL(stat, this);
+                       return;
+               }
+               if (alias != null && value.getClass().isEnum()) {
+                       // special case:
+                       // value is first enum constant which is also the alias object.
+                       // the first enum constant is used as the alias because we can not
+                       // instantiate an enum reflectively.
+                       stat.appendSQL("?");
+                       addParameter(stat, alias, value);
+                       return;
+               }
+               SelectColumn<T> col = getColumnByReference(value);
+               if (col != null) {
+                       col.appendSQL(stat);
+                       return;
+               }
+               stat.appendSQL("?");
+               addParameter(stat, alias, value);
+       }
+
+       /**
+        * INTERNAL
+        *
+        * @param stat
+        *            the statement
+        * @param alias
+        *            the alias object (can be null)
+        * @param valueLeft
+        *            the value on the left of the compound clause
+        * @param valueRight
+        *            the value on the right of the compound clause
+        * @param compareType
+        *            the current compare type (e.g. BETWEEN)
+        */
+       public void appendSQL(SQLStatement stat, Object alias, Object valueLeft, Object valueRight,
+                       CompareType compareType) {
+               stat.appendSQL("?");
+               stat.appendSQL(" ");
+               switch (compareType) {
+               case BETWEEN:
+                       stat.appendSQL("AND");
+                       break;
+               }
+               stat.appendSQL(" ");
+               stat.appendSQL("?");
+               addParameter(stat, alias, valueLeft);
+               addParameter(stat, alias, valueRight);
+       }
+
+       public void appendSQL(SQLStatement stat, Object alias, Iterable<Object> values,
+                       CompareType compareType) {
+               boolean first = true;
+               stat.appendSQL("(");
+               for (Object value : values) {
+                       if (first) {
+                               first = false;
+                       } else {
+                               stat.appendSQL(", ");
+                       }
+                       stat.appendSQL("?");
+                       addParameter(stat, alias, value);
+               }
+               stat.appendSQL(")");
+       }
+
+       private void addParameter(SQLStatement stat, Object alias, Object value) {
+               SelectColumn<T> col = getColumnByReference(alias);
+               if (col != null && value.getClass().isEnum()) {
+                       // enum
+                       EnumType type = col.getFieldDefinition().enumType;
+                       Enum<?> anEnum = (Enum<?>) value;
+                       Object y = Utils.convertEnum(anEnum, type);
+                       stat.addParameter(y);
+               } else if (col != null) {
+                       // object
+                       Class<? extends DataTypeAdapter<?>> typeAdapter = col.getFieldDefinition().typeAdapter;
+                       Object parameter = db.getDialect().serialize(value, typeAdapter);
+                       stat.addParameter(parameter);
+               } else {
+                       // primitive
+                       stat.addParameter(value);
+               }
+       }
+
+       void addConditionToken(Token condition) {
+               if (condition == ConditionOpenClose.OPEN) {
+                       conditionDepth ++;
+               } else if (condition == ConditionOpenClose.CLOSE) {
+                       conditionDepth --;
+                       if (conditionDepth < 0) {
+                               throw new IciqlException("unmatch condition open-close count");
+                       }
+               }
+               conditions.add(condition);
+       }
+
+       void addConditionToken(Query<T> other) {
+               for (Token condition : other.conditions) {
+                       addConditionToken(condition);
+               }
+       }
+
+       void addUpdateColumnDeclaration(UpdateColumn declaration) {
+               updateColumnDeclarations.add(declaration);
+       }
+
+       void appendWhere(SQLStatement stat) {
+               if (conditionDepth != 0) {
+                       throw new IciqlException("unmatch condition open-close count");
+               }
+               if (!conditions.isEmpty()) {
+                       stat.appendSQL(" WHERE ");
+
+                       boolean skipNextConjunction = false;
+
+                       for (Token token : conditions) {
+
+                               if (skipNextConjunction && token instanceof ConditionAndOr) {
+                                       skipNextConjunction = false;
+                                       continue;
+                               }
+
+                               token.appendSQL(stat, this);
+                               stat.appendSQL(" ");
+
+                               if (ConditionOpenClose.OPEN == token) {
+                                       skipNextConjunction = true;
+                               }
+                       }
+               }
+       }
+
+       void appendFromWhere(SQLStatement stat) {
+               appendFromWhere(stat, true);
+       }
+
+       void appendFromWhere(SQLStatement stat, boolean log) {
+               stat.appendSQL(" FROM ");
+               from.appendSQL(stat);
+               for (SelectTable<T> join : joins) {
+                       join.appendSQLAsJoin(stat, this);
+               }
+               appendWhere(stat);
+               if (!groupByExpressions.isEmpty()) {
+                       stat.appendSQL(" GROUP BY ");
+                       int i = 0;
+                       for (Object obj : groupByExpressions) {
+                               if (i++ > 0) {
+                                       stat.appendSQL(", ");
+                               }
+                               appendSQL(stat, null, obj);
+                               stat.appendSQL(" ");
+                       }
+               }
+               if (!orderByList.isEmpty()) {
+                       stat.appendSQL(" ORDER BY ");
+                       int i = 0;
+                       for (OrderExpression<T> o : orderByList) {
+                               if (i++ > 0) {
+                                       stat.appendSQL(", ");
+                               }
+                               o.appendSQL(stat);
+                               stat.appendSQL(" ");
+                       }
+               }
+               db.getDialect().appendLimitOffset(stat, limit, offset);
+               if (log) {
+                       IciqlLogger.select(stat.getSQL());
+               }
+       }
+
+       /**
+        * Join another table.
+        *
+        * @param alias
+        *            an alias for the table to join
+        * @return the joined query
+        */
+
+       public <A> QueryJoin<T> innerJoin(A alias) {
+        return join(alias, false);
+       }
+
+    public <A> QueryJoin<T> leftJoin(A alias) {
+        return join(alias, true);
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private <A> QueryJoin<T> join(A alias, boolean outerJoin) {
+        TableDefinition<T> def = (TableDefinition<T>) db.define(alias.getClass());
+        SelectTable<T> join = new SelectTable(db, this, alias, outerJoin);
+        def.initSelectObject(join, alias, aliasMap, false);
+        joins.add(join);
+        return new QueryJoin(this, join);
+    }
+
+       Db getDb() {
+               return db;
+       }
+
+       SelectTable<T> getFrom() {
+               return from;
+       }
+
+       boolean isJoin() {
+               return !joins.isEmpty();
+       }
+
+       SelectTable<?> getSelectTable(Object alias) {
+               if (from.getAlias() == alias) {
+                       return from;
+               } else {
+                       for (SelectTable<?> join : joins) {
+                               if (join.getAlias() == alias) {
+                                       return join;
+                               }
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * This method returns a mapped Object field by its reference.
+        *
+        * @param obj
+        * @return
+        */
+       private SelectColumn<T> getColumnByReference(Object obj) {
+               SelectColumn<T> col = aliasMap.get(obj);
+               return col;
+       }
+
+       /**
+        * This method returns the alias of a mapped primitive field by its value.
+        *
+        * @param obj
+        * @return
+        */
+       @SuppressWarnings("unchecked")
+       <A> A getPrimitiveAliasByValue(A obj) {
+               for (Object alias : aliasMap.keySet()) {
+                       if (alias.equals(obj)) {
+                               SelectColumn<T> match = aliasMap.get(alias);
+                               if (match.getFieldDefinition().isPrimitive) {
+                                       return (A) alias;
+                               }
+                       }
+               }
+               return null;
+       }
+
+       void addOrderBy(OrderExpression<T> expr) {
+               orderByList.add(expr);
+       }
+
+}
index 11b1af8c3f921d675e8bf269923fc0316dd2b3e0..ccc04529fbeddffcd6c9d428fd76bc51c2670587 100644 (file)
@@ -37,20 +37,21 @@ public interface SQLDialect {
        void registerAdapter(DataTypeAdapter<?> typeAdapter);
 
        /**
-        * Returns the registered instance of the type adapter for the specified object class.
+        * Returns the registered instance of the type adapter.
         *
-        * @param objectClass
+        * @param typeAdapter
         * @return the type adapter instance
         */
-       DataTypeAdapter<?> getAdapter(Class<?> objectClass);
+       DataTypeAdapter<?> getAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter);
 
        /**
         * Serialize the Java object into a type or format that the database will accept.
         *
         * @param value
+        * @param typeAdapter
         * @return the serialized object
         */
-       <T> Object serialize(T value);
+       <T> Object serialize(T value, Class<? extends DataTypeAdapter<?>> typeAdapter);
 
        /**
         * Deserialize the object received from the database into a Java type.
@@ -58,9 +59,10 @@ public interface SQLDialect {
         * @param rs
         * @param columnIndex
         * @param targetType
+        * @param typeAdapter
         * @return the deserialized object
         */
-       Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType);
+       Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType, Class<? extends DataTypeAdapter<?>> typeAdapter);
 
        /**
         * Configure the dialect.
index 19b0fcd4a911b12e63bb1dd671f05b2b39cbfb7a..e5b6ca60b5fd6ff0c72bda38a895e98f4b42beed 100644 (file)
@@ -55,10 +55,10 @@ public class SQLDialectDefault implements SQLDialect {
        String databaseName;
        String productVersion;
        Mode mode;
-       Map<Class<?>, DataTypeAdapter<?>> typeAdapters;
+       Map<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>> typeAdapters;
 
        public SQLDialectDefault() {
-               typeAdapters = new ConcurrentHashMap<Class<?>, DataTypeAdapter<?>>();
+               typeAdapters = new ConcurrentHashMap<Class<? extends DataTypeAdapter<?>>, DataTypeAdapter<?>>();
        }
 
        @Override
@@ -420,7 +420,7 @@ public class SQLDialectDefault implements SQLDialect {
                        buff.appendExceptFirst(", ");
                        buff.append('?');
                        Object value = def.getValue(obj, field);
-                       Object parameter = serialize(value);
+                       Object parameter = serialize(value, field.typeAdapter);
                        stat.addParameter(parameter);
                }
                buff.append(" FROM ");
@@ -432,7 +432,7 @@ public class SQLDialectDefault implements SQLDialect {
                                buff.appendExceptFirst(" AND ");
                                buff.append(MessageFormat.format("{0} = ?", prepareColumnName(field.columnName)));
                                Object value = def.getValue(obj, field);
-                               Object parameter = serialize(value);
+                               Object parameter = serialize(value, field.typeAdapter);
                                stat.addParameter(parameter);
                        }
                }
@@ -452,35 +452,37 @@ public class SQLDialectDefault implements SQLDialect {
 
        @Override
        public void registerAdapter(DataTypeAdapter<?> typeAdapter) {
-               typeAdapters.put(typeAdapter.getJavaType(), typeAdapter);
+               typeAdapters.put((Class<? extends DataTypeAdapter<?>>) typeAdapter.getClass(), typeAdapter);
        }
 
        @Override
-       public DataTypeAdapter<?> getAdapter(Class<?> objectClass) {
-               DataTypeAdapter<?> dta = typeAdapters.get(objectClass);
-               if (dta != null) {
-                       dta.setMode(mode);
+       public DataTypeAdapter<?> getAdapter(Class<? extends DataTypeAdapter<?>> typeAdapter) {
+               DataTypeAdapter<?> dta = typeAdapters.get(typeAdapter);
+               if (dta == null) {
+                       dta = Utils.newObject(typeAdapter);
+                       typeAdapters.put(typeAdapter, dta);
                }
+               dta.setMode(mode);
                return dta;
        }
 
        @SuppressWarnings("unchecked")
        @Override
-       public <T> Object serialize(T value) {
-               DataTypeAdapter dta = getAdapter(value.getClass());
-               if (dta == null) {
+       public <T> Object serialize(T value, Class<? extends DataTypeAdapter<?>> typeAdapter) {
+               if (typeAdapter == null) {
                        // pass-through
                        return value;
                }
+
+               DataTypeAdapter<T> dta = (DataTypeAdapter<T>) getAdapter(typeAdapter);
                return dta.serialize(value);
        }
 
        @Override
-       public Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType) {
+       public Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType, Class<? extends DataTypeAdapter<?>> typeAdapter) {
                Object value = null;
                try {
-                       DataTypeAdapter<?> dta = getAdapter(targetType);
-                       if (dta == null) {
+                       if (typeAdapter == null) {
                                // standard object deserialization
                                Object o = rs.getObject(columnIndex);
                                if (o == null) {
@@ -495,6 +497,7 @@ public class SQLDialectDefault implements SQLDialect {
                                }
                        } else {
                                // custom object deserialization with a DataTypeAdapter
+                               DataTypeAdapter<?> dta = getAdapter(typeAdapter);
                                Object object = rs.getObject(columnIndex);
                                value = dta.deserialize(object);
                        }
@@ -521,4 +524,4 @@ public class SQLDialectDefault implements SQLDialect {
                return o.toString();
        }
 
-}
\ No newline at end of file
+}
index 206937c8cd3c83d11ae3b2f29b603e21420cddc4..2d7d0fd7039518b72d0fa79c1644921a251d1d0f 100644 (file)
@@ -127,7 +127,7 @@ public class SQLDialectH2 extends SQLDialectDefault {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       Object parameter = serialize(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
                        stat.addParameter(parameter);\r
                }\r
                buff.append(')');\r
index 44256671bbc1fa1d1fac2f6e8439447e568ea2d3..8b05ca4b7f6ae1eb6af0dcbf462b778a5675fb69 100644 (file)
@@ -91,7 +91,7 @@ public class SQLDialectHSQL extends SQLDialectDefault {
                        }\r
                        buff.append(')');\r
                        Object value = def.getValue(obj, field);\r
-                       Object parameter = serialize(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
                        stat.addParameter(parameter);\r
                }\r
 \r
index ea19384a2416efdfdb47b9101b381fcfb3e8fe34..ec5923f6eb7c53bbb3a8a84f35820676809a137d 100644 (file)
@@ -77,7 +77,7 @@ public class SQLDialectMySQL extends SQLDialectDefault {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       Object parameter = serialize(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
                        stat.addParameter(parameter);\r
                }\r
                buff.append(") ON DUPLICATE KEY UPDATE ");\r
index acb9b31e934824d6bcdc2a18fb980761d66e32e6..436af54f4c3044a47299aab8d284d46d2ce0f94b 100644 (file)
@@ -22,6 +22,7 @@ import java.sql.SQLException;
 import java.sql.Time;\r
 import java.sql.Timestamp;\r
 \r
+import com.iciql.Iciql.DataTypeAdapter;\r
 import com.iciql.TableDefinition.FieldDefinition;\r
 import com.iciql.TableDefinition.IndexDefinition;\r
 import com.iciql.util.IciqlLogger;\r
@@ -131,7 +132,7 @@ public class SQLDialectSQLite extends SQLDialectDefault {
                        buff.appendExceptFirst(", ");\r
                        buff.append('?');\r
                        Object value = def.getValue(obj, field);\r
-                       Object parameter = serialize(value);\r
+                       Object parameter = serialize(value, field.typeAdapter);\r
                        stat.addParameter(parameter);\r
                }\r
                buff.append(')');\r
@@ -139,11 +140,11 @@ public class SQLDialectSQLite extends SQLDialectDefault {
        }\r
 \r
        @Override\r
-       public Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType) {\r
+       public Object deserialize(ResultSet rs, int columnIndex, Class<?> targetType, Class<? extends DataTypeAdapter<?>> typeAdapter) {\r
                try {\r
-                       return super.deserialize(rs, columnIndex, targetType);\r
+                       return super.deserialize(rs, columnIndex, targetType, typeAdapter);\r
                } catch (IciqlException e) {\r
-                       if (e.getMessage().startsWith("Can not convert")) {\r
+                       if (typeAdapter == null && e.getMessage().startsWith("Can not convert")) {\r
                                try {\r
                                        // give the SQLite JDBC driver an opportunity to deserialize DateTime objects\r
                                        if (Timestamp.class.equals(targetType)) {\r
@@ -176,4 +177,4 @@ public class SQLDialectSQLite extends SQLDialectDefault {
                }\r
                return super.prepareStringParameter(o);\r
        }\r
-}
\ No newline at end of file
+}
index 6ed94627ef1cfdac2c63b9bbb6b92614319a221b..8248f187edf8f8c18446ddb04e8b897737039332 100644 (file)
@@ -475,9 +475,8 @@ public class TableDefinition<T> {
                        }
 
                        if (typeAdapter != null) {
-                               DataTypeAdapter<?> dta = Utils.newObject(typeAdapter);
-                               dataType = dta.getDataType();
-                               db.getDialect().registerAdapter(dta);
+                               DataTypeAdapter<?> dtt = db.getDialect().getAdapter(typeAdapter);
+                               dataType = dtt.getDataType();
                        }
 
                        boolean hasAnnotation = f.isAnnotationPresent(IQColumn.class);
@@ -674,7 +673,7 @@ public class TableDefinition<T> {
                                // try to interpret and instantiate a default value
                                value = ModelUtils.getDefaultValue(field, db.getDialect().getDateTimeClass());
                        }
-                       Object parameter = db.getDialect().serialize(value);
+                       Object parameter = db.getDialect().serialize(value, field.typeAdapter);
                        stat.addParameter(parameter);
                }
                buff.append(')');
@@ -710,7 +709,7 @@ public class TableDefinition<T> {
                                // try to interpret and instantiate a default value
                                value = ModelUtils.getDefaultValue(field, db.getDialect().getDateTimeClass());
                        }
-                       Object parameter = db.getDialect().serialize(value);
+                       Object parameter = db.getDialect().serialize(value, field.typeAdapter);
                        stat.addParameter(parameter);
                }
                buff.append(')');
@@ -785,7 +784,7 @@ public class TableDefinition<T> {
                                buff.appendExceptFirst(", ");
                                buff.append(db.getDialect().prepareColumnName(field.columnName));
                                buff.append(" = ?");
-                               Object parameter = db.getDialect().serialize(value);
+                               Object parameter = db.getDialect().serialize(value, field.typeAdapter);
                                stat.addParameter(parameter);
                        }
                }
@@ -1178,7 +1177,7 @@ public class TableDefinition<T> {
                                }
                                o = Utils.convertEnum(obj, targetType, def.enumType);
                        } else {
-                               o = dialect.deserialize(rs, columns[i], targetType);
+                               o = dialect.deserialize(rs, columns[i], targetType, def.typeAdapter);
                        }
                        def.setValue(item, o);
                }