diff options
Diffstat (limited to 'src')
128 files changed, 6377 insertions, 0 deletions
diff --git a/src/com/iciql/CompareType.java b/src/main/java/com/iciql/CompareType.java index 84e29fe..84e29fe 100644 --- a/src/com/iciql/CompareType.java +++ b/src/main/java/com/iciql/CompareType.java diff --git a/src/com/iciql/Condition.java b/src/main/java/com/iciql/Condition.java index 17cb117..17cb117 100644 --- a/src/com/iciql/Condition.java +++ b/src/main/java/com/iciql/Condition.java diff --git a/src/com/iciql/ConditionAndOr.java b/src/main/java/com/iciql/ConditionAndOr.java index 4d1cd0e..4d1cd0e 100644 --- a/src/com/iciql/ConditionAndOr.java +++ b/src/main/java/com/iciql/ConditionAndOr.java diff --git a/src/com/iciql/Constants.java b/src/main/java/com/iciql/Constants.java index 8b54493..8b54493 100644 --- a/src/com/iciql/Constants.java +++ b/src/main/java/com/iciql/Constants.java diff --git a/src/com/iciql/Db.java b/src/main/java/com/iciql/Db.java index ecd373c..ecd373c 100644 --- a/src/com/iciql/Db.java +++ b/src/main/java/com/iciql/Db.java diff --git a/src/com/iciql/DbInspector.java b/src/main/java/com/iciql/DbInspector.java index acaceea..acaceea 100644 --- a/src/com/iciql/DbInspector.java +++ b/src/main/java/com/iciql/DbInspector.java diff --git a/src/com/iciql/DbUpgrader.java b/src/main/java/com/iciql/DbUpgrader.java index 1303f4e..1303f4e 100644 --- a/src/com/iciql/DbUpgrader.java +++ b/src/main/java/com/iciql/DbUpgrader.java diff --git a/src/com/iciql/DbVersion.java b/src/main/java/com/iciql/DbVersion.java index 6270e14..6270e14 100644 --- a/src/com/iciql/DbVersion.java +++ b/src/main/java/com/iciql/DbVersion.java diff --git a/src/com/iciql/Define.java b/src/main/java/com/iciql/Define.java index 1810a4b..1810a4b 100644 --- a/src/com/iciql/Define.java +++ b/src/main/java/com/iciql/Define.java diff --git a/src/com/iciql/Filter.java b/src/main/java/com/iciql/Filter.java index 99dbdc3..99dbdc3 100644 --- a/src/com/iciql/Filter.java +++ b/src/main/java/com/iciql/Filter.java diff --git a/src/com/iciql/Function.java b/src/main/java/com/iciql/Function.java index 3faddb7..3faddb7 100644 --- a/src/com/iciql/Function.java +++ b/src/main/java/com/iciql/Function.java diff --git a/src/com/iciql/Iciql.java b/src/main/java/com/iciql/Iciql.java index 9f73ffa..9f73ffa 100644 --- a/src/com/iciql/Iciql.java +++ b/src/main/java/com/iciql/Iciql.java diff --git a/src/com/iciql/IciqlException.java b/src/main/java/com/iciql/IciqlException.java index 3f27b73..3f27b73 100644 --- a/src/com/iciql/IciqlException.java +++ b/src/main/java/com/iciql/IciqlException.java diff --git a/src/com/iciql/ModelUtils.java b/src/main/java/com/iciql/ModelUtils.java index 56e6440..56e6440 100644 --- a/src/com/iciql/ModelUtils.java +++ b/src/main/java/com/iciql/ModelUtils.java diff --git a/src/com/iciql/OrderExpression.java b/src/main/java/com/iciql/OrderExpression.java index f450bfb..f450bfb 100644 --- a/src/com/iciql/OrderExpression.java +++ b/src/main/java/com/iciql/OrderExpression.java diff --git a/src/com/iciql/Query.java b/src/main/java/com/iciql/Query.java index 5dc78a5..5dc78a5 100644 --- a/src/com/iciql/Query.java +++ b/src/main/java/com/iciql/Query.java diff --git a/src/com/iciql/QueryBetween.java b/src/main/java/com/iciql/QueryBetween.java index 72d19dc..72d19dc 100644 --- a/src/com/iciql/QueryBetween.java +++ b/src/main/java/com/iciql/QueryBetween.java diff --git a/src/com/iciql/QueryCondition.java b/src/main/java/com/iciql/QueryCondition.java index 9613b1b..9613b1b 100644 --- a/src/com/iciql/QueryCondition.java +++ b/src/main/java/com/iciql/QueryCondition.java diff --git a/src/com/iciql/QueryJoin.java b/src/main/java/com/iciql/QueryJoin.java index 6d0484e..6d0484e 100644 --- a/src/com/iciql/QueryJoin.java +++ b/src/main/java/com/iciql/QueryJoin.java diff --git a/src/com/iciql/QueryJoinCondition.java b/src/main/java/com/iciql/QueryJoinCondition.java index 6dfd218..6dfd218 100644 --- a/src/com/iciql/QueryJoinCondition.java +++ b/src/main/java/com/iciql/QueryJoinCondition.java diff --git a/src/com/iciql/QueryWhere.java b/src/main/java/com/iciql/QueryWhere.java index 5baa5ab..5baa5ab 100644 --- a/src/com/iciql/QueryWhere.java +++ b/src/main/java/com/iciql/QueryWhere.java diff --git a/src/com/iciql/RuntimeParameter.java b/src/main/java/com/iciql/RuntimeParameter.java index 0fbedba..0fbedba 100644 --- a/src/com/iciql/RuntimeParameter.java +++ b/src/main/java/com/iciql/RuntimeParameter.java diff --git a/src/com/iciql/RuntimeToken.java b/src/main/java/com/iciql/RuntimeToken.java index cbfd882..cbfd882 100644 --- a/src/com/iciql/RuntimeToken.java +++ b/src/main/java/com/iciql/RuntimeToken.java diff --git a/src/com/iciql/SQLDialect.java b/src/main/java/com/iciql/SQLDialect.java index f62168e..f62168e 100644 --- a/src/com/iciql/SQLDialect.java +++ b/src/main/java/com/iciql/SQLDialect.java diff --git a/src/com/iciql/SQLDialectDefault.java b/src/main/java/com/iciql/SQLDialectDefault.java index 364db7b..364db7b 100644 --- a/src/com/iciql/SQLDialectDefault.java +++ b/src/main/java/com/iciql/SQLDialectDefault.java diff --git a/src/com/iciql/SQLDialectDerby.java b/src/main/java/com/iciql/SQLDialectDerby.java index f954a7c..f954a7c 100644 --- a/src/com/iciql/SQLDialectDerby.java +++ b/src/main/java/com/iciql/SQLDialectDerby.java diff --git a/src/com/iciql/SQLDialectH2.java b/src/main/java/com/iciql/SQLDialectH2.java index 6b3bab1..6b3bab1 100644 --- a/src/com/iciql/SQLDialectH2.java +++ b/src/main/java/com/iciql/SQLDialectH2.java diff --git a/src/com/iciql/SQLDialectHSQL.java b/src/main/java/com/iciql/SQLDialectHSQL.java index 82e6833..82e6833 100644 --- a/src/com/iciql/SQLDialectHSQL.java +++ b/src/main/java/com/iciql/SQLDialectHSQL.java diff --git a/src/com/iciql/SQLDialectMSSQL.java b/src/main/java/com/iciql/SQLDialectMSSQL.java index 92b1297..92b1297 100644 --- a/src/com/iciql/SQLDialectMSSQL.java +++ b/src/main/java/com/iciql/SQLDialectMSSQL.java diff --git a/src/com/iciql/SQLDialectMySQL.java b/src/main/java/com/iciql/SQLDialectMySQL.java index 52676d4..52676d4 100644 --- a/src/com/iciql/SQLDialectMySQL.java +++ b/src/main/java/com/iciql/SQLDialectMySQL.java diff --git a/src/com/iciql/SQLDialectPostgreSQL.java b/src/main/java/com/iciql/SQLDialectPostgreSQL.java index fc115ab..fc115ab 100644 --- a/src/com/iciql/SQLDialectPostgreSQL.java +++ b/src/main/java/com/iciql/SQLDialectPostgreSQL.java diff --git a/src/com/iciql/SQLStatement.java b/src/main/java/com/iciql/SQLStatement.java index 394fc42..394fc42 100644 --- a/src/com/iciql/SQLStatement.java +++ b/src/main/java/com/iciql/SQLStatement.java diff --git a/src/com/iciql/SelectColumn.java b/src/main/java/com/iciql/SelectColumn.java index 43a1a93..43a1a93 100644 --- a/src/com/iciql/SelectColumn.java +++ b/src/main/java/com/iciql/SelectColumn.java diff --git a/src/com/iciql/SelectTable.java b/src/main/java/com/iciql/SelectTable.java index 37b42c4..37b42c4 100644 --- a/src/com/iciql/SelectTable.java +++ b/src/main/java/com/iciql/SelectTable.java diff --git a/src/com/iciql/SubQuery.java b/src/main/java/com/iciql/SubQuery.java index 398d214..398d214 100644 --- a/src/com/iciql/SubQuery.java +++ b/src/main/java/com/iciql/SubQuery.java diff --git a/src/com/iciql/SubQueryCondition.java b/src/main/java/com/iciql/SubQueryCondition.java index effea3b..effea3b 100644 --- a/src/com/iciql/SubQueryCondition.java +++ b/src/main/java/com/iciql/SubQueryCondition.java diff --git a/src/com/iciql/TableDefinition.java b/src/main/java/com/iciql/TableDefinition.java index 6d8cb6e..6d8cb6e 100644 --- a/src/com/iciql/TableDefinition.java +++ b/src/main/java/com/iciql/TableDefinition.java diff --git a/src/com/iciql/TableInspector.java b/src/main/java/com/iciql/TableInspector.java index b717203..b717203 100644 --- a/src/com/iciql/TableInspector.java +++ b/src/main/java/com/iciql/TableInspector.java diff --git a/src/com/iciql/TestCondition.java b/src/main/java/com/iciql/TestCondition.java index 010f5a1..010f5a1 100644 --- a/src/com/iciql/TestCondition.java +++ b/src/main/java/com/iciql/TestCondition.java diff --git a/src/com/iciql/Token.java b/src/main/java/com/iciql/Token.java index cc2203c..cc2203c 100644 --- a/src/com/iciql/Token.java +++ b/src/main/java/com/iciql/Token.java diff --git a/src/com/iciql/UpdateColumn.java b/src/main/java/com/iciql/UpdateColumn.java index 1eaf14c..1eaf14c 100644 --- a/src/com/iciql/UpdateColumn.java +++ b/src/main/java/com/iciql/UpdateColumn.java diff --git a/src/com/iciql/UpdateColumnIncrement.java b/src/main/java/com/iciql/UpdateColumnIncrement.java index 143ce48..143ce48 100644 --- a/src/com/iciql/UpdateColumnIncrement.java +++ b/src/main/java/com/iciql/UpdateColumnIncrement.java diff --git a/src/com/iciql/UpdateColumnSet.java b/src/main/java/com/iciql/UpdateColumnSet.java index a961480..a961480 100644 --- a/src/com/iciql/UpdateColumnSet.java +++ b/src/main/java/com/iciql/UpdateColumnSet.java diff --git a/src/com/iciql/ValidationRemark.java b/src/main/java/com/iciql/ValidationRemark.java index 33320ab..33320ab 100644 --- a/src/com/iciql/ValidationRemark.java +++ b/src/main/java/com/iciql/ValidationRemark.java diff --git a/src/com/iciql/bytecode/And.java b/src/main/java/com/iciql/bytecode/And.java index 808a9c1..808a9c1 100644 --- a/src/com/iciql/bytecode/And.java +++ b/src/main/java/com/iciql/bytecode/And.java diff --git a/src/com/iciql/bytecode/ArrayGet.java b/src/main/java/com/iciql/bytecode/ArrayGet.java index 29516c2..29516c2 100644 --- a/src/com/iciql/bytecode/ArrayGet.java +++ b/src/main/java/com/iciql/bytecode/ArrayGet.java diff --git a/src/com/iciql/bytecode/CaseWhen.java b/src/main/java/com/iciql/bytecode/CaseWhen.java index 2a1d69e..2a1d69e 100644 --- a/src/com/iciql/bytecode/CaseWhen.java +++ b/src/main/java/com/iciql/bytecode/CaseWhen.java diff --git a/src/com/iciql/bytecode/ClassReader.java b/src/main/java/com/iciql/bytecode/ClassReader.java index 38fd2f5..38fd2f5 100644 --- a/src/com/iciql/bytecode/ClassReader.java +++ b/src/main/java/com/iciql/bytecode/ClassReader.java diff --git a/src/com/iciql/bytecode/Constant.java b/src/main/java/com/iciql/bytecode/Constant.java index 65cd66b..65cd66b 100644 --- a/src/com/iciql/bytecode/Constant.java +++ b/src/main/java/com/iciql/bytecode/Constant.java diff --git a/src/com/iciql/bytecode/ConstantNumber.java b/src/main/java/com/iciql/bytecode/ConstantNumber.java index 934de3d..934de3d 100644 --- a/src/com/iciql/bytecode/ConstantNumber.java +++ b/src/main/java/com/iciql/bytecode/ConstantNumber.java diff --git a/src/com/iciql/bytecode/ConstantString.java b/src/main/java/com/iciql/bytecode/ConstantString.java index 985f97d..985f97d 100644 --- a/src/com/iciql/bytecode/ConstantString.java +++ b/src/main/java/com/iciql/bytecode/ConstantString.java diff --git a/src/com/iciql/bytecode/Function.java b/src/main/java/com/iciql/bytecode/Function.java index 56a55ea..56a55ea 100644 --- a/src/com/iciql/bytecode/Function.java +++ b/src/main/java/com/iciql/bytecode/Function.java diff --git a/src/com/iciql/bytecode/Not.java b/src/main/java/com/iciql/bytecode/Not.java index ab5ab84..ab5ab84 100644 --- a/src/com/iciql/bytecode/Not.java +++ b/src/main/java/com/iciql/bytecode/Not.java diff --git a/src/com/iciql/bytecode/Null.java b/src/main/java/com/iciql/bytecode/Null.java index a28de56..a28de56 100644 --- a/src/com/iciql/bytecode/Null.java +++ b/src/main/java/com/iciql/bytecode/Null.java diff --git a/src/com/iciql/bytecode/Operation.java b/src/main/java/com/iciql/bytecode/Operation.java index 7cd42d9..7cd42d9 100644 --- a/src/com/iciql/bytecode/Operation.java +++ b/src/main/java/com/iciql/bytecode/Operation.java diff --git a/src/com/iciql/bytecode/Or.java b/src/main/java/com/iciql/bytecode/Or.java index 37da2a6..37da2a6 100644 --- a/src/com/iciql/bytecode/Or.java +++ b/src/main/java/com/iciql/bytecode/Or.java diff --git a/src/com/iciql/bytecode/Variable.java b/src/main/java/com/iciql/bytecode/Variable.java index f3dbc01..f3dbc01 100644 --- a/src/com/iciql/bytecode/Variable.java +++ b/src/main/java/com/iciql/bytecode/Variable.java diff --git a/src/com/iciql/bytecode/package.html b/src/main/java/com/iciql/bytecode/package.html index 5107481..5107481 100644 --- a/src/com/iciql/bytecode/package.html +++ b/src/main/java/com/iciql/bytecode/package.html diff --git a/src/com/iciql/package.html b/src/main/java/com/iciql/package.html index 769837b..769837b 100644 --- a/src/com/iciql/package.html +++ b/src/main/java/com/iciql/package.html diff --git a/src/com/iciql/util/GenerateModels.java b/src/main/java/com/iciql/util/GenerateModels.java index eac9f6c..eac9f6c 100644 --- a/src/com/iciql/util/GenerateModels.java +++ b/src/main/java/com/iciql/util/GenerateModels.java diff --git a/src/com/iciql/util/IciqlLogger.java b/src/main/java/com/iciql/util/IciqlLogger.java index d8005bb..d8005bb 100644 --- a/src/com/iciql/util/IciqlLogger.java +++ b/src/main/java/com/iciql/util/IciqlLogger.java diff --git a/src/com/iciql/util/JdbcUtils.java b/src/main/java/com/iciql/util/JdbcUtils.java index 4a4a2b6..4a4a2b6 100644 --- a/src/com/iciql/util/JdbcUtils.java +++ b/src/main/java/com/iciql/util/JdbcUtils.java diff --git a/src/com/iciql/util/Slf4jIciqlListener.java b/src/main/java/com/iciql/util/Slf4jIciqlListener.java index ded393f..ded393f 100644 --- a/src/com/iciql/util/Slf4jIciqlListener.java +++ b/src/main/java/com/iciql/util/Slf4jIciqlListener.java diff --git a/src/com/iciql/util/StatementBuilder.java b/src/main/java/com/iciql/util/StatementBuilder.java index 47e8054..47e8054 100644 --- a/src/com/iciql/util/StatementBuilder.java +++ b/src/main/java/com/iciql/util/StatementBuilder.java diff --git a/src/com/iciql/util/StringUtils.java b/src/main/java/com/iciql/util/StringUtils.java index dd3f180..dd3f180 100644 --- a/src/com/iciql/util/StringUtils.java +++ b/src/main/java/com/iciql/util/StringUtils.java diff --git a/src/com/iciql/util/Utils.java b/src/main/java/com/iciql/util/Utils.java index 77110b8..77110b8 100644 --- a/src/com/iciql/util/Utils.java +++ b/src/main/java/com/iciql/util/Utils.java diff --git a/src/com/iciql/util/WeakIdentityHashMap.java b/src/main/java/com/iciql/util/WeakIdentityHashMap.java index bc03cd0..bc03cd0 100644 --- a/src/com/iciql/util/WeakIdentityHashMap.java +++ b/src/main/java/com/iciql/util/WeakIdentityHashMap.java diff --git a/src/com/iciql/util/package.html b/src/main/java/com/iciql/util/package.html index 3d24dee..3d24dee 100644 --- a/src/com/iciql/util/package.html +++ b/src/main/java/com/iciql/util/package.html diff --git a/src/site/00_index.mkd b/src/site/00_index.mkd new file mode 100644 index 0000000..1c2bbd3 --- /dev/null +++ b/src/site/00_index.mkd @@ -0,0 +1,63 @@ +## Overview
+
+iciql **is**...
+
+- a model-based, database access wrapper for JDBC
+- for modest database schemas and basic statement generation
+- for those who want to write code, instead of SQL, using IDE completion and compile-time type-safety
+- small (200KB) with debug symbols and no runtime dependencies
+- pronounced *icicle* (although it could be French: *ici ql* - here query language)
+- a friendly fork of the H2 [JaQu][jaqu] project
+
+iciql **is not**...
+
+- a complete alternative to JDBC
+- designed to compete with more powerful database query tools like [jOOQ][jooq] or [Querydsl][querydsl]
+- designed to compete with enterprise [ORM][orm] tools like [Hibernate][hibernate] or [mybatis][mybatis]
+
+### Example Usage
+<table class="table">
+<tr>
+<th>iciql</th><th>sql</th>
+</tr>
+<tr>
+<td>
+%BEGINCODE%
+Product p = new Product();
+List<Product> restock = db.from(p).where(p.unitsInStock).is(0).select();
+List<Product> all = db.executeQuery(Product.class, "select * from products");
+%ENDCODE%
+
+</td><td>
+<br/>
+select * from products p where p.unitsInStock = 0<br/>
+select * from products
+</td>
+</tr>
+</table>
+
+### Supported Databases (Unit-Tested)
+- [H2](http://h2database.com) ${h2.version}
+- [HSQLDB](http://hsqldb.org) ${hsqldb.version}
+- [Derby](http://db.apache.org/derby) ${derby.version}
+- [MySQL](http://mysql.com) ${mysql.version}
+- [PostgreSQL](http://postgresql.org) ${postgresql.version}
+
+Support for others is possible and may only require creating a simple "dialect" class.
+
+### Java Runtime Requirement
+
+iciql requires a Java 6 Runtime Environment (JRE) or a Java 6 Development Kit (JDK).
+
+### License
+iciql is distributed under the terms of the [Apache Software Foundation license, version 2.0][apachelicense]
+
+[jaqu]: http://h2database.com/html/jaqu.html "H2 JaQu project"
+[orm]: http://en.wikipedia.org/wiki/Object-relational_mapping "Object Relational Mapping"
+[jooq]: http://jooq.sourceforge.net "jOOQ"
+[querydsl]: http://source.mysema.com/display/querydsl/Querydsl "Querydsl"
+[hibernate]: http://www.hibernate.org "Hibernate"
+[mybatis]: http://www.mybatis.org "mybatis"
+[github]: http://github.com/gitblit/iciql "iciql git repository"
+[googlecode]: http://code.google.com/p/iciql "iciql project management"
+[apachelicense]: http://www.apache.org/licenses/LICENSE-2.0 "Apache License, Version 2.0"
\ No newline at end of file diff --git a/src/site/01_model_classes.mkd b/src/site/01_model_classes.mkd new file mode 100644 index 0000000..8fedf18 --- /dev/null +++ b/src/site/01_model_classes.mkd @@ -0,0 +1,335 @@ +## Model Classes
+A model class represents a single table within your database. Fields within your model class represent columns in the table. The object types of your fields are reflectively mapped to SQL types by iciql at runtime.
+
+Models can be manually written using one of three approaches: *annotation configuration*, *interface configuration*, or *POJO configuration*. All approaches can be used within a project and all can be used within a single model class, although that is discouraged.
+
+Alternatively, model classes can be automatically generated by iciql using the model generation tool. Please see the [tools](tools.html) page for details.
+
+### Configuration Requirements and Limitations
+
+1. Your model class **must** provide a public default constructor.
+2. All **Object** fields are assumed NULLABLE unless explicitly set *@IQColumn(nullable = false)* or *Define.nullable(field, false)*.
+3. All **Primitive** fields are assumed NOT NULLABLE unless explicitly set *@IQColumn(nullable = true)* or *Define.nullable(field, true)*.
+4. Only the specified types are supported. Any other types are not supported.
+5. Triggers, views, and other advanced database features are not supported.
+
+### Supported Data Types
+
+---NOMARKDOWN---
+<table class="table">
+<tr><td colspan="3"><b>Fully Supported Types</b><br/>
+can be used for all iciql expressions
+</tr>
+<tr><th>Object</th><th>Primitive</th><th>SQL Type</th></tr>
+<tr><td>java.lang.String</td><td></td>
+<td>VARCHAR <em>(length > 0)</em> or CLOB <em>(length == 0)</em></td></tr>
+
+<tr><td>java.lang.Boolean</td><td>boolean</td>
+<td>BOOLEAN<br/><i>can only <b>declare and explicitly reference</b> one <u>primitive boolean</u> per model<br/>multiple primitives are allowed if not using where/set/on/and/or/groupBy/orderBy(boolean)</i></td></tr>
+
+<tr><td>java.lang.Byte</td><td>byte</td>
+<td>TINYINT</td></tr>
+
+<tr><td>java.lang.Short</td><td>short</td>
+<td>SMALLINT</td></tr>
+
+<tr><td>java.lang.Integer</td><td>int</td>
+<td>INT</td></tr>
+
+<tr><td>java.lang.Long</td><td>long</td>
+<td>BIGINT</td></tr>
+
+<tr><td>java.lang.Float</td><td>float</td>
+<td>REAL</td></tr>
+
+<tr><td>java.lang.Double</td><td>double</td>
+<td>DOUBLE</td></tr>
+
+<tr><td>java.math.BigDecimal</td><td> </td>
+<td>DECIMAL <em>(length == 0)</em> or DECIMAL(length,scale) <em>(length > 0)</em></td></tr>
+
+<tr><td>java.sql.Date</td><td> </td>
+<td>DATE</td></tr>
+
+<tr><td>java.sql.Time</td><td> </td>
+<td>TIME</td></tr>
+
+<tr><td>java.sql.Timestamp</td><td> </td>
+<td>TIMESTAMP</td></tr>
+
+<tr><td>java.util.Date</td><td> </td>
+<td>TIMESTAMP</td></tr>
+
+<tr><td>java.lang.Enum.name()<br/><em>default type</em></td><td></td>
+<td>VARCHAR <em>(length > 0)</em> or CLOB <em>(length == 0)</em><br/><em>EnumType.NAME</em><br/><i>can only <b>declare and explicitly reference</b> one instance of <u>each enum type</u> per model<br/>multiple instances of an enum type within a model is allowed if not using where/set/on/and/or/groupBy/orderBy(enum)</i></td></tr>
+
+<tr><td>java.lang.Enum.ordinal()</td><td> </td>
+<td>INT<br/><em>EnumType.ORDINAL</em><br/><i>can only <b>declare and explicitly reference</b> one instance of <u>each enum type</u> per model<br/>multiple instances of an enum type within a model is allowed if not using where/set/on/and/or/groupBy/orderBy(enum)</i></td></tr>
+
+<tr><td>java.lang.Enum implements<br/><em>com.iciql.Iciql.EnumId.enumId()</em></td><td> </td>
+<td>INT<br/><em>EnumType.ENUMID</em><br/><i>can only <b>declare and explicitly reference</b> one instance of <u>each enum type</u> per model<br/>multiple instances of an enum type within a model is allowed if not using where/set/on/and/or/groupBy/orderBy(enum)</i></td></tr>
+
+<tr><td colspan="3"><b>Partially Supported Types</b><br/>
+can not be directly referenced in an expression</td></tr>
+<tr><td>byte []</td> <td></td>
+<td>BLOB</td><tr/>
+
+<tr><td colspan="3"><b>H2 Database Types</b><br/>
+fully supported when paired with an H2 database
+</td></tr>
+<tr><td>java.util.UUID</td><td> </td>
+<td>UUID</td></tr>
+
+</table>
+---NOMARKDOWN---
+**NOTE:**<br/>
+The reverse lookup used for model generation, SQL type -> Java type, contains more mappings.<br/>
+Please consult the `com.iciql.ModelUtils` class for details.
+
+## Annotation Configuration
+The recommended approach to setup a model class is to annotate the class and field declarations.
+
+### advantages
+
+- annotated models support annotated field inheritance making it possible to design a single base class that defines the fields and then create table subclasses that specify the table mappings.
+- model runtime dependency is limited to the small, portable `com.iciql.Iciql` class file which contains the annotation definitions
+
+### disadvantages
+
+- more verbose model classes
+- indexes are defined using "fragile" string column names
+- compound primary keys are defined using "fragile" string column names
+
+### field mapping
+
+- By default, **ONLY** fields annotated with *@IQColumn* are mapped.
+- scope is irrelevant.
+- transient is irrelevant.
+
+### default values
+
+You may specify default values for an *@IQColumn* by either:
+
+1. specifying the default value string within your annotation<br/>
+**NOTE:**<br/>
+The annotated default value always takes priority over a field default value.
+%BEGINCODE%
+// notice the single ticks!
+@IQColumn(defaultValue="'2000-01-01 00:00:00'")
+Date myDate;
+%ENDCODE%
+
+2. setting a default value on the field<br/>
+**NOTE:**<br/>
+Primitive types have an implicit default value of *0* or *false*.
+%BEGINCODE%
+@IQColumn
+Date myDate = new Date(100, 0, 1);
+
+@IQColumn
+int myId;
+%ENDCODE%
+
+If you want to specify a database-specific variable or function as your default value (e.g. CURRENT_TIMESTAMP) you must do that within the annotation. Also note that the *IQColumn.defaultValue* must be a well-formatted SQL DEFAULT expression whereas object defaults will be automatically converted to an SQL DEFAULT expression.
+
+### Special Case: primitive autoincrement fields and 0
+%BEGINCODE%
+@IQColumn(autoIncrement = true)
+int myId;
+%ENDCODE%
+
+Because primitive types have implicit default values, this field will be excluded from an INSERT statement if its value is 0. Iciql can not differentiate an implicit/uninitialized 0 from a explicitly assigned 0.
+
+### Example Annotated Model
+%BEGINCODE%
+import com.iciql.Iciql.EnumType;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQEnum;
+import com.iciql.Iciql.IQIndex;
+import com.iciql.Iciql.IQTable;
+
+@IQTable
+@IQIndexes({
+ @IQIndex({"productName", "category"}),
+ @IQIndex(name="nameindex", value="productName")
+})
+public class Product {
+
+ @IQEnum(EnumType.ORDINAL)
+ public enum Availability {
+ ACTIVE, DISCONTINUED;
+ }
+
+ @IQColumn(primaryKey = true)
+ public Integer productId;
+
+ @IQColumn(length = 200, trim = true)
+ public String productName;
+
+ @IQColumn(length = 50, trim = true)
+ public String category;
+
+ @IQColumn
+ public Double unitPrice;
+
+ @IQColumn(name = "units")
+ public Integer unitsInStock;
+
+ @IQColumn
+ private Integer reorderQuantity;
+
+ @IQColumn
+ private Availability availability;
+
+ // ignored because it is not annotated AND the class is @IQTable annotated
+ private Integer ignoredField;
+
+ public Product() {
+ // default constructor
+ }
+}
+%ENDCODE%
+
+## Interface Configuration
+Alternatively, you may map your model classes using the interface approach by implementing the `com.iciql.Iciql` interface.
+
+This is a less verbose configuration style, but it comes at the expense of introducing a compile-time dependency on the logic of the iciql library. This might be a deterrent, for example, if you were serializing your model classes to another process that may not have the iciql library.
+
+The `com.iciql.Iciql` interface specifies a single method, *defineIQ()*. In your implementation of *defineIQ()* you would use static method calls to set:
+
+- the schema name
+- the table name (if it's not the class name)
+- the column name (if it's not the field name)
+- the max length and trim of a string field
+- the precision and scale of a decimal field
+- the autoincrement flag of a long or integer field
+- the nullable flag of a field
+- the primaryKey (single field or compound)
+- any indexes (single field or compound)
+
+### advantages
+
+- less verbose model class
+- compile-time index definitions
+- compile-time compound primary key definitions
+
+### disadvantages
+
+- model runtime dependency on entire iciql library
+- *defineIQ()* is called from a static synchronized block which may be a bottleneck for highly concurrent systems
+
+### field mapping
+
+- **ALL** fields are mapped unless annotated with *@IQIgnore*.
+- scope is irrelevant.
+- transient is irrelevant.
+
+### default values
+
+You may specify default values for an field by either:
+
+1. specifying the default value string within your *defineIQ()* method<br/>
+**NOTE:**<br/>
+The defineIQ() value always takes priority over a field default value.
+%BEGINCODE%
+Date myDate;
+
+public void defineIQ() {
+ // notice the single ticks!
+ Define.defaultValue(myDate, "'2000-01-01 00:00:00'");
+}
+%ENDCODE%
+
+2. setting a default value on the field<br/>
+**NOTE:**<br/>
+Primitive types have an implicit default value of *0* or *false*.
+%BEGINCODE%
+Date myDate = new Date(100, 0, 1);
+
+int myId;
+%ENDCODE%
+
+### Example Interface Model
+%BEGINCODE%
+import com.iciql.Iciql;
+import com.iciql.Iciql.IQIgnore;
+
+public class Product implements Iciql {
+ public Integer productId;
+ public String productName;
+ public String category;
+ public Double unitPrice;
+ public Integer unitsInStock;
+
+ @IQIgnore
+ Integer reorderQuantity;
+
+ public Product() {
+ }
+
+ @Override
+ public void defineIQ() {
+ com.iciql.Define.primaryKey(productId);
+ com.iciql.Define.columnName(unitsInStock, "units");
+ com.iciql.Define.length(productName, 200);
+ com.iciql.Define.length(category, 50);
+ com.iciql.Define.index(productName, category);
+ }
+}
+%ENDCODE%
+
+
+## POJO (Plain Old Java Object) Configuration
+
+This approach is very similar to the *interface configuration* approach; it is the least verbose and also the least useful.
+
+This approach would be suitable for quickly modeling an existing table where only SELECT and INSERT statements will be generated.
+
+### advantages
+
+- nearly zero-configuration
+
+### disadvantages
+
+- can not execute DELETE, UPDATE, or MERGE statements (they require a primary key specification)
+- table name MUST MATCH model class name
+- column names MUST MATCH model field names
+- can not specify any column attributes
+- can not specify indexes
+
+### field mapping
+
+- **ALL** fields are mapped unless annotated with *@IQIgnore*.
+- scope is irrelevant.
+- transient is irrelevant.
+
+### default values
+
+You may specify a default value on the field.
+
+**NOTE:**<br/>
+Primitive types have an implicit default value of *0* or *false*.
+%BEGINCODE%
+Date myDate = new Date(100, 0, 1);
+
+int myId;
+%ENDCODE%
+
+### Example POJO Model
+%BEGINCODE%
+import com.iciql.Iciql.IQIgnore;
+
+public class Product {
+ public Integer productId;
+ public String productName;
+ public String category;
+ public Double unitPrice;
+ public Integer units;
+
+ @IQIgnore
+ Integer reorderQuantity;
+
+ public Product() {
+ }
+}
+%ENDCODE%
\ No newline at end of file diff --git a/src/site/02_table_versioning.mkd b/src/site/02_table_versioning.mkd new file mode 100644 index 0000000..2e95aaa --- /dev/null +++ b/src/site/02_table_versioning.mkd @@ -0,0 +1,29 @@ +## Database & Table Versioning
+
+Iciql supports an optional, simple versioning mechanism. There are two parts to the mechanism.
+
+1. You must supply an implementation of `com.iciql.DbUpgrader` to your `com.iciql.Db` instance.
+2. One or more of your table model classes must specify the `IQVersion(version)` annotation<br/>
+AND/OR<br/>
+Your `com.iciql.DbUpgrader` implementation must specify the `IQVersion(version)` annotation
+
+### How does it work?
+If you choose to use versioning, iciql will maintain a table within your database named *iq_versions* which is defined as:
+
+ CREATE TABLE IQ_VERSIONS(SCHEMANAME VARCHAR(255) NOT NULL, TABLENAME VARCHAR(255) NOT NULL, VERSION INT NOT NULL)
+
+This database table is automatically created if and only if at least one of your model classes specifies a *version* > 0.
+
+When you generate a statement, iciql will compare the annotated version field of your model class to its last known value in the *iq_versions* table. If *iq_versions* lags behind the model annotation, iciql will immediately call the registered `com.iciql.DbUpgrader` implementation before generating and executing the current statement.
+
+When an upgrade scenario is identified, the current version and the annotated version information is passed to either:
+
+- `DbUpgrader.upgradeDatabase(db, fromVersion, toVersion)`
+- `DbUpgrader.upgradeTable(db, schema, table, fromVersion, toVersion)`
+
+both of which allow for non-linear upgrades. If the upgrade method call is successful and returns *true*, iciql will update the *iq_versions* table with the annotated version number.
+
+The actual upgrade procedure is beyond the scope of iciql and is your responsibility to implement. This is simply a mechanism to automatically identify when an upgrade is necessary.
+
+**NOTE:**<br/>
+The database entry of the *iq_versions* table is specified as SCHEMANAME='' and TABLENAME=''.
\ No newline at end of file diff --git a/src/site/02_usage.mkd b/src/site/02_usage.mkd new file mode 100644 index 0000000..7b9d89d --- /dev/null +++ b/src/site/02_usage.mkd @@ -0,0 +1,197 @@ +## Usage
+
+Aside from this brief usage guide, please consult the [examples](examples.html), the [javadoc](javadoc.html) and the [source code](${project.scmUrl}).
+
+### Instantiating a Db
+
+Use one of the static utility methods to instantiate a Db instance:
+
+ Db.open(String url, String user, String password);
+ Db.open(String url, String user, char[] password);
+ Db.open(Connection conn);
+ Db.open(DataSource dataSource);
+
+### Compile-Time Statements
+
+You compose your statements using the builder pattern where each method call returns an object that is used to specify the next part of the statement. Through clever usage of generics, pioneered by the original JaQu project, compile-time safety flows through the statement.
+
+%BEGINCODE%
+Db db = Db.open("jdbc:h2:mem:", "sa", "sa");
+db.insertAll(Product.getList());
+db.insertAll(Customer.getList());
+
+List<Product> restock =
+ db.from(p).
+ where(p.unitsInStock).
+ is(0).orderBy(p.productId).select();
+
+for (Product product : restock) {
+ db.from(p).
+ set(p.unitsInStock).to(25).
+ where(p.productId).is(product.productId).update();
+}
+db.close();
+%ENDCODE%
+
+Please see the [examples](examples.html) page for more code samples.
+
+### Dynamic Runtime Queries
+
+Iciql gives you compile-time type-safety, but it becomes inconvenient if your design requires more dynamic statement generation. For these scenarios iciql offers some runtime query support through a hybrid approach or a pure JDBC approach.
+
+#### Where String Fragment Approach
+This approach is a mixture of iciql and jdbc. It uses the traditional prepared statement *field=?* tokens with iciql compile-time model class type checking. There is no field token type-safety checking.
+%BEGINCODE%
+List<Product> restock = db.from(p).where("unitsInStock=? and productName like ? order by productId", 0, "Chef%").select();
+%ENDCODE%
+
+#### Db.executeQuery Approaches
+There may be times when the hybrid approach is still too restrictive and you'd prefer to write straight SQL. You can do that too and use iciql to build objects from your ResultSet, but be careful:
+
+1. Make sure to _select *_ in your query otherwise db.buildObjects() will throw a RuntimeException
+2. There is no model class type checking nor field type checking.
+
+%BEGINCODE%
+List<Product> allProducts = db.executeQuery(Product.class, "select * from products");
+List<Product> restock = db.executeQuery(Product.class, "select * from products where unitsInStock=?", 0);
+
+// parameterized query which can be cached and re-used later
+String q = db.from(p).where(p.unitsInStock).isParameter().toSQL();
+List<Product> restock = db.executeQuery(Product.class, q, 0);
+
+%ENDCODE%
+
+Or if you want access to the raw *ResultSet* before building your model object instances...
+
+%BEGINCODE%
+ResultSet rs = db.executeQuery("select * from products");
+List<Product> allProducts = db.buildObjects(Product.class, rs);
+// This method ensures the creating statement is closed
+JdbcUtils.closeSilently(rs, true);
+%ENDCODE%
+
+### Natural Syntax
+
+<span class="warning">work-in-progress</span>
+
+The original JaQu source offers partial support for Java expressions in *where* clauses.
+
+This works by decompiling a Java expression, at runtime, to an SQL condition. The expression is written as an anonymous inner class implementation of the `com.iciql.Filter` interface.
+A proof-of-concept decompiler is included, but is incomplete.
+
+The proposed syntax is:
+%BEGINCODE%
+long count = db.from(co).
+ where(new Filter() { public boolean where() {
+ return co.id == x
+ && co.name.equals(name)
+ && co.value == new BigDecimal("1")
+ && co.amount == 1L
+ && co.birthday.before(new java.util.Date())
+ && co.created.before(java.sql.Timestamp.valueOf("2005-05-05 05:05:05"))
+ && co.time.before(java.sql.Time.valueOf("23:23:23"));
+ }
+ }).selectCount();
+%ENDCODE%
+
+### JDBC Statements, ResultSets, and Exception Handling
+
+Iciql opens and closes all JDBC objects automatically. SQLExceptions thrown during execution of a statement (except for *close()* calls), will be caught, wrapped, and rethrown as an `IciqlException`, which is a RuntimeException.
+
+Iciql does not throw any [checked exceptions](http://en.wikipedia.org/wiki/Exception_handling#Checked_exceptions).
+
+### Statement Logging
+
+Iciql provides a mechanism to log generated statements and warnings to the console, to SLF4J, or to your own logging framework. Exceptions are not logged using this mechanism; exceptions are wrapped and rethrown as `IciqlException`, which is a RuntimeException.
+
+#### Console Logging
+%BEGINCODE%
+IciqlLogger.activeConsoleLogger();
+IciqlLogger.deactiveConsoleLogger();
+%ENDCODE%
+
+#### SLF4J Logging
+%BEGINCODE%
+Slf4jIciqlListener slf4j = new Slf4jIciqlListener();
+slf4j.setLevel(StatementType.CREATE, Level.WARN);
+slf4j.setLevel(StatementType.DELETE, Level.WARN);
+slf4j.setLevel(StatementType.MERGE, Level.OFF);
+IciqlLogger.registerListener(slf4j);
+IciqlLogger.unregisterListener(slf4j);
+%ENDCODE%
+
+#### Custom Logging
+%BEGINCODE%
+IciqlListener custom = new IciqlListener() {
+ public void logIciql(StatementType type, String statement) {
+ // do log
+ }
+};
+IciqlLogger.registerListener(custom);
+IciqlLogger.unregisterListener(custom);
+%ENDCODE%
+
+## Understanding Aliases and Model Classes
+Consider the following example:
+%BEGINCODE%
+Product p = new Product();
+List<Product> restock = db.from(p).where(p.unitsInStock).is(0).select();
+%ENDCODE%
+
+The Product model class instance named **p** is an *alias* object. An *alias* is simply an instance of your model class that is only used to build the compile-time/runtime representation of your table.
+
+1. *Alias* instances are **NOT** thread-safe and must not be used concurrently.
+2. *Alias* instances have no other purpose than to provide a compile-time/runtime map of your table.
+3. If you inspected an *alias* instance after using one you would find that it's fields have been assigned numeric values.<br/>These values are assigned from a static counter in `com.iciql.Utils.newObject()` during execution of the *db.from()* method.<p/>For *Object* fields, these values are meaningless since objects are mapped by reference.<br/>For *Primitive* fields these values do matter because primitives are mapped by value. The proper alias is selected as long as the primitive variant methods are used. e.g. db.from(p).where(int).is(Integer).select()
+
+If your statement is a query, like in the above example, iciql will generate new instances of your *alias* model class and return them as a list where each entry of the list represents a row from the JDBC `ResultSet`.
+
+### Why are Aliases not thread-safe?
+
+The _db.from(p)_ call reinstantiates each member field of p. Those reinstantiated fields are then subsequently used in clauses like _where(p.unitsInStock)_. If your *alias* instance is shared concurrently then its highly probable that when _queryA_ executes, _queryC_ has reinstantiated all the *alias* fields and broken _queryA's_ runtime field mapping.
+
+Depending on your design, you might consider using a [ThreadLocal](http://download.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html) variable if you do not want to keep instantiating *alias* instances. A utility function is included for easily creating ThreadLocal variables.
+
+%BEGINCODE%
+final ThreadLocal<Product> p = Utils.newThreadLocal(Product.class);
+db.from(p.get()).select();
+%ENDCODE%
+
+## Best Practices
+
+1. Close your *Db* instances when you are done with them, this closes the underlying connection or directs the pool to "close" the connection.
+2. Aliases instances are not thread-safe so DO NOT SHARE an alias!<br/>Consider using a *ThreadLocal* alias instance with the `com.iciql.Utils.newThreadLocal()` utility method.
+
+<p/>
+<table class="table">
+<tr><th>Not Thread-Safe</th><th>Thread-Safe</th></tr>
+<tr><td>
+%BEGINCODE%
+final Product p = new Product();
+for (int i = 0; i < 5; i++) {
+ Thread thread = new Thread(new Runnable() {
+ public void run() {
+ // from(p) reinstantiates p's fields
+ db.from(p).select();
+ }
+ }, "Thread-" + i);
+ thread.start();
+}
+%ENDCODE%
+
+</td><td>
+%BEGINCODE%
+final ThreadLocal<Product> p = Utils.newThreadLocal(Product.class);
+for (int i = 0; i < 5; i++) {
+ Thread thread = new Thread(new Runnable() {
+ public void run() {
+ // a unique p for this thread
+ db.from(p.get()).select();
+ }
+ }, "Thread-" + i);
+ thread.start();
+}
+%ENDCODE%
+
+</td></tr>
+</table>
\ No newline at end of file diff --git a/src/site/03_performance.mkd b/src/site/03_performance.mkd new file mode 100644 index 0000000..34e545c --- /dev/null +++ b/src/site/03_performance.mkd @@ -0,0 +1,22 @@ +
+## Performance
+
+The information provided here may be based on flawed test procedures. You have to be the judge of what is performant and non-performant.
+
+### iciql statement generation
+
+Performance of iciql statement generation is not currently benchmarked.
+
+### iciql+database performance comparison
+
+The following data was generated by running the *single-threaded* iciql test suite. All database connections are pooled and re-used within each execution of the test suite using [Apache Commons DBCP](http://commons.apache.org/dbcp).
+
+Connections are pooled to normalize embedded database performance with out-of-process database performance. Some of the Java embedded database configurations have a very high startup-time penalty. Notably, H2 is slow to open a database and its performance is substantially affected if connection pooling is not enabled to keep the embedded database open.
+
+All tables are created as CACHED when the database distinguishes between CACHED and MEMORY tables.
+
+All performance numbers include the combined overhead of iciql statement generation and JUnit 4 test framework execution so they are not bare-metal database metrics.
+
+<pre>
+%DBPERFORMANCE%
+</pre>
\ No newline at end of file diff --git a/src/site/04_examples.mkd b/src/site/04_examples.mkd new file mode 100644 index 0000000..33cb9c4 --- /dev/null +++ b/src/site/04_examples.mkd @@ -0,0 +1,196 @@ +## Select Statements
+
+%BEGINCODE%
+// select * from products
+List<Product> allProducts = db.from(p).select();
+
+// select * from customers where region='WA'
+Customer c = new Customer();
+List<Customer> waCustomers = db.from(c). where(c.region).is("WA").select();
+
+public static class ProductPrice {
+ public String productName;
+ public String category;
+ public Double price;
+}
+
+// select with generation of new anonymous inner class
+List<ProductPrice> productPrices =
+ db.from(p).
+ orderBy(p.productId).
+ select(new ProductPrice() {{
+ productName = p.productName;
+ category = p.category;
+ price = p.unitPrice;
+ }});
+%ENDCODE%
+
+## Insert Statements
+
+%BEGINCODE%
+// single record insertion
+db.insert(singleProduct);
+
+// single record insertion with primary key retrieval
+Long key = db.insertAndGetKey(singleProduct);
+
+// batch record insertion
+db.insertAll(myProducts);
+
+// batch insertion with primary key retrieval
+List<Long> myKeys = db.insertAllAndGetKeys(list);
+%ENDCODE%
+
+## Update Statements
+
+%BEGINCODE%
+// single record update
+db.update(singleProduct);
+
+// batch record updates
+db.updateAll(myProducts);
+
+// update query
+db.from(p).set(p.productName).to("updated")
+ .increment(p.unitPrice).by(3.14)
+ .increment(p.unitsInStock).by(2)
+ .where(p.productId).is(1).update();
+
+// reusable, parameterized update query
+String q = db.from(p).set(p.productName).toParameter().where(p.productId).is(1).toSQL();
+db.executeUpdate(q, "Lettuce");
+
+%ENDCODE%
+
+## Merge Statements
+Merge statements currently generate the [H2 merge syntax](http://h2database.com/html/grammar.html#merge).
+
+%BEGINCODE%
+Product pChang = db.from(p).where(p.productName).is("Chang").selectFirst();
+pChang.unitPrice = 19.5;
+pChang.unitsInStock = 16;
+db.merge(pChang);
+%ENDCODE%
+
+## Delete Statements
+
+%BEGINCODE%
+// single record deletion
+db.delete(singleProduct);
+
+// batch record deletion
+db.deleteAll(myProducts);
+
+// delete query
+db.from(p).where(p.productId).atLeast(10).delete();
+
+%ENDCODE%
+
+## Inner Join Statements
+
+%BEGINCODE%
+final Customer c = new Customer();
+final Order o = new Order();
+
+List<Customer> customersWithLargeOrders =
+ db.from(c).
+ innerJoin(o).on(c.customerId).is(o.customerId).
+ where(o.total).greaterThan(new BigDecimal("500.00")).
+ groupBy(c.customerId).select();
+
+
+List<CustOrder> orders =
+ db.from(c).
+ innerJoin(o).on(c.customerId).is(o.customerId).
+ where(o.total).lessThan(new BigDecimal("500.00")).
+ orderBy(1).
+ select(new CustOrder() {{
+ customerId = c.customerId;
+ orderId = o.orderId;
+ total = o.total;
+ }});
+%ENDCODE%
+
+## View Statements
+
+%BEGINCODE%
+// the view named "ProductView" is created from the "Products" table
+@IQView(viewTableName = "Products")
+public class ProductView {
+
+ @IQColumn
+ @IQConstraint("this >= 200 AND this < 300")
+ Long id;
+
+ @IQColumn
+ String name;
+}
+
+final ProductView v = new ProductView();
+List<ProductView> allProducts = db.from(v).select();
+
+// this version of the view model "ProductView" inherits table metadata
+// from the Products class which is annotated with IQTable
+@IQView(inheritColumns = true)
+public class ProductView extends Products {
+
+ // inherited BUT replaced to define the constraint
+ @IQColumn
+ @IQConstraint("this >= 200 AND this < 300")
+ Long id;
+
+ // inherited from Products
+ //@IQColumn
+ //String name;
+}
+
+final ProductView v = new ProductView();
+List<ProductView> allProducts = db.from(v).select();
+
+// in this example we are creating a view based on a fluent query
+// and using 2 levels of inheritance. IQConstraints are ignored
+// when using this approach because we are fluently defining them.
+@IQView(inheritColumns = true)
+public class ProductViewInherited extends ProductView {
+
+}
+
+final Products p = new Products();
+db.from(p).where(p.id).atLeast(200L).and(p.id).lessThan(300L).createView(ProductViewInherited.class);
+
+// now replace the view with a variation
+db.from(p).where(p.id).atLeast(250L).and(p.id).lessThan(350L).replaceView(ProductViewInherited.class);
+
+// now drop the view from the database
+db.dropView(ProductViewInherited.class);
+
+%ENDCODE%
+
+## Dynamic Queries
+
+Dynamic queries skip all field type checking and, depending on which approach you use, may skip model class/table name checking too.
+
+%BEGINCODE%
+// where fragment with object parameters
+List<Product> restock = db.from(p).where("unitsInStock=? and productName like ? order by productId", 0, "Chef%").select();
+
+// parameterized query which can be cached and re-used later
+String q = db.from(p).where(p.unitsInStock).isParameter().and(p.productName).likeParameter().orderBy(p.productId).toSQL();
+List<Product> allProducts = db.executeQuery(Product.class, q, 0, "Chef%");
+
+// statement with binding to your model class
+List<Product> allProducts = db.executeQuery(Product.class, "select * from products");
+
+// statement with object parameters and binding to your model class
+List<Product> restock = db.executeQuery(Product.class, "select * from products where unitsInStock=?", 0);
+
+/**
+ * If you want to process the intermediate ResultSet
+ * yourself make sure to use the <i>closeSilently()</i> method
+ * to ensure the parent statement is closed too.
+ */
+ResultSet rs = db.executeQuery("select * from products");
+List<Product> allProducts = db.buildObjects(Product.class, rs);
+JdbcUtils.closeSilently(rs, true);
+
+%ENDCODE%
\ No newline at end of file diff --git a/src/site/04_tools.mkd b/src/site/04_tools.mkd new file mode 100644 index 0000000..6d8c348 --- /dev/null +++ b/src/site/04_tools.mkd @@ -0,0 +1,95 @@ +## Model Generation
+If you do not have or do not want to annotate your existing model classes, you can use the included model generation tool to create iciql model classes.
+
+ java -jar iciql.jar <parameters>
+
+### Parameters
+<table class="table">
+<tr><th>-url</th><td>JDBC url for the database</td><td><em>REQUIRED</em></td></tr>
+<tr><th>-username</th><td>username for JDBC connection</td><td><em>optional</em></td></tr>
+<tr><th>-password</th><td>password for JDBC connection</td><td><em>optional</em></td></tr>
+<tr><th>-schema</th><td>the target schema for model generation</td><td><em>default:</em> all schemas</td></tr>
+<tr><th>-table</th><td>the target table for model generation</td><td><em>default:</em> all tables</td></tr>
+<tr><th>-package</th><td>the destination package name for generated models</td><td><em>default:</em> default package</td></tr>
+<tr><th>-folder</th><td>the output folder for .java files</td><td><em>default:</em> current folder</td></tr>
+<tr><th>-annotateSchema</th><td>include the schema name in the class annotations</td><td><em>default:</em> true</td></tr>
+<tr><th>-trimStrings</th><td>annotate trimStrings=true for any VARCHAR string mappings </td><td><em>default:</em> false</td></tr>
+</table>
+
+## Model Validation
+Iciql can validate your model classes against your database to ensure that your models are optimally defined and are consistent with the current table and index definitions.
+
+Each `com.iciql.ValidationRemark` returned by the validation has an associated level from the following enum:
+%BEGINCODE%
+public static enum Level {
+ CONSIDER, WARN, ERROR;
+}
+%ENDCODE%
+
+A typical validation may output recommendations for adjusting a model field annotation such as setting the *maxLength* of a string to match the length of its linked VARCHAR column.
+
+### Sample Model Validation using JUnit 4
+%BEGINCODE%
+import static org.junit.Assert.assertTrue;
+
+import java.sql.SQLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ErrorCollector;
+
+import com.iciql.Db;
+import com.iciql.DbInspector;
+import com.iciql.ValidationRemark;
+import com.iciql.test.models.Product;
+import com.iciql.test.models.ProductAnnotationOnly;
+import com.iciql.test.models.ProductMixedAnnotation;
+
+public class ValidateModels {
+
+ /*
+ * The ErrorCollector Rule allows execution of a test to continue after the
+ * first problem is found and report them all at once
+ */
+ @Rule
+ public ErrorCollector errorCollector = new ErrorCollector();
+
+ private Db db;
+
+ @Before
+ public void setUp() {
+ db = Db.open("jdbc:h2:mem:", "sa", "sa");
+ }
+
+ @After
+ public void tearDown() {
+ db.close();
+ }
+
+ @Test
+ public void testValidateModels() {
+ DbInspector inspector = new DbInspector(db);
+ validateModel(inspector, new Product());
+ validateModel(inspector, new ProductAnnotationOnly());
+ validateModel(inspector, new ProductMixedAnnotation());
+ }
+
+ private void validateModel(DbInspector inspector, Object o) {
+ List<ValidationRemark> remarks = inspector.validateModel(o, false);
+ assertTrue("Validation remarks are null for " + o.getClass().getName(), remarks != null);
+ log("Validation remarks for " + o.getClass().getName());
+ for (ValidationRemark remark : remarks) {
+ log(remark.toString());
+ if (remark.isError()) {
+ errorCollector.addError(new SQLException(remark.toString()));
+ }
+ }
+ }
+
+ private void log(String message) {
+ System.out.println(message);
+ }
+}
+%ENDCODE%
\ No newline at end of file diff --git a/src/site/05_building.mkd b/src/site/05_building.mkd new file mode 100644 index 0000000..b5548bc --- /dev/null +++ b/src/site/05_building.mkd @@ -0,0 +1,35 @@ +## Building from Source
+
+[Eclipse](http://eclipse.org) is recommended for development as the project settings are preconfigured.
+
+Additionally, [eclipse-cs](http://eclipse-cs.sourceforge.net), [FindBugs](http://findbugs.sourceforge.net), and [EclEmma](http://www.eclemma.org) are recommended development tools.
+
+### Build Dependencies (bundled in repository)
+- [ant-googlecode](http://code.google.com/p/ant-googlecode) (New BSD)
+
+### Build Dependencies (downloaded during build)
+- [Moxie Build Toolkit](http://moxie.gitblit.com) (Apache 2.0)
+- [H2 Database](http://h2database.com) (Eclipse Public License 1.0)
+- [HSQL Database Engine](http://hsqldb.org) (BSD)
+- [Apache Derby Database](http://db.apache.org/derby) (Apache 2.0)
+- [MySQL Connector/J](http://dev.mysql.com/downloads/connector/j) (GPL)
+- [PostgreSQL JDBC Connector](http://jdbc.postgresql.org) (BSD)
+- [JUnit](http://junit.org) (Common Public License)
+- [SLF4J](http://www.slf4j.org) (MIT/X11)
+- [Apache Commons Pool](http://commons.apache.org/pool) (Apache 2.0)
+- [Apache Commons DBCP](http://commons.apache.org/dbcp) (Apache 2.0)
+
+### Instructions
+1. Clone the git repository from [Github](${project.scmUrl}).
+2. Import the iciql project into your Eclipse workspace.<br/>
+*There will be some build errors.*
+3. Using Ant, execute the `build.xml` script in the project root.<br/>
+*This will download all necessary build dependencies.*
+4. Select your iciql project root and **Refresh** the project, this should correct all build problems.
+
+## Contributing
+Patches welcome in any form.
+
+Contributions must be your own original work and must licensed under the [Apache License, Version 2.0][apachelicense], the same license used by iciql.
+
+[apachelicense]: http://www.apache.org/licenses/LICENSE-2.0 "Apache License, Version 2.0"
\ No newline at end of file diff --git a/src/site/05_javadoc.mkd b/src/site/05_javadoc.mkd new file mode 100644 index 0000000..0d0f161 --- /dev/null +++ b/src/site/05_javadoc.mkd @@ -0,0 +1,7 @@ +<div class="javadoc_nav">
+<a href="javadoc/overview-summary.html" target="javadoc">packages</a>
+ | <a href="javadoc/overview-tree.html" target="javadoc">tree</a>
+ | <a href="javadoc/deprecated-list.html" target="javadoc">deprecated</a>
+ | <a href="javadoc/index-all.html" target="javadoc">index</a>
+</div>
+<iframe name="javadoc" src="javadoc/overview-summary.html" width="100%" height="650" frameborder="0"></iframe>
diff --git a/src/site/05_releases.mkd b/src/site/05_releases.mkd new file mode 100644 index 0000000..3e66494 --- /dev/null +++ b/src/site/05_releases.mkd @@ -0,0 +1,223 @@ +## Release History
+
+### Current Release
+
+**${project.version}**
+
+- Fixed case-sensitivity bug on setting a compound primary key from an annotation (issue 12)
+- Implemented readonly view support. (issue 8)<br/>
+View models may be specified using the IQView annotation or Iciql.define(). Views can either be created automatically as part of a query of the view OR views may be constructed from a fluent statement.
+- Support inheriting columns from super.super class, if super.super is annotated.<br/>This allows for an inheritance hierarchy like:<br/>
+@IQTable class MyTable -> @IQView abstract class MyBaseView -> @IQView class MyConstrainedView
+- Fixed order of DEFAULT value in create table statement (issue 11)
+- Support inheritance of IQVersion for DbUpgrader implementations (issue 10)
+- Fixed password bug in model generator (issue 7)
+
+### Older Releases
+
+**1.1.0** *released 2012-08-20*
+
+- All bulk operations (insert all, update all, delete all) now use JDBC savepoints to ensure atomicity of the transaction
+
+**1.0.0** *released 2012-07-14*
+
+- Issue CREATE TABLE and CREATE INDEX statements once per-db instance/table-mapping
+- Fixed bug in using 0L primitive values in where clauses. These were confused with the COUNT(*) function. (Github/kc5nra,issue 5)
+- Added support for single column subquery *select name, address from user_table where user_id in (select user_id from invoice table where paid = false)*
+- Added support for left outer join (Github/backpaper0)
+
+**0.7.10** *released 2012-01-27*
+
+- Fixed default String value bug where a default empty string threw an IndexOutOfBounds exception
+
+**0.7.9** *released 2012-01-24*
+
+- Added toParameter() option for SET commands and allow generating parameterized UPDATE statements<br/>
+String q = db.from(t).set(t.timestamp).toParameter().where(t.id).is(5).toSQL();<br/>
+db.executeUpdate(q, new Date());
+
+**0.7.8** *released 2012-01-11*
+
+- Replaced non-threadsafe counter used for assigning AS identifiers in JOIN statements with an AtomicInteger
+- Prevent negative rollover of the AS counter
+- Added optional alias parameter to *Query.toSQL* and *QueryWhere.toSQL* to force generated statement to prefix an AS identifier or, alternatively, the tablename.
+ - Query.toSQL(boolean distinct, K alias)
+ - QueryWhere.toSQL(boolean distinct, K alias)
+- Fixed bug in Query.select(Z z) which assumed that Z must always be an anonymous inner class which may not always be true. This allows for specifying an existing alias to force table or identifier usage in the generated select list. This is very useful for DISTINCT JOIN statements where only the columns of the primary table are of interest.
+
+**0.7.7** *released 2012-01-05*
+
+- added *Query.toSQL()* and *QueryWhere.toSQL()* methods which, when combined with the following new methods, allows for generation of a parameterized, static sql string to be reused with a dynamic query or a PreparedStatement.
+ - QueryCondition.isParameter()
+ - QueryCondition.atLeastParameter()
+ - QueryCondition.atMostParameter()
+ - QueryCondition.exceedsParameter()
+ - QueryCondition.lessThanParameter()
+ - QueryCondition.likeParameter()
+ - QueryCondition.isNotParameter()
+- Disallow **declaring and explicitly referencing** multiple instances of an enum type within a single model.<br/>A runtime exception will be thrown if an attempt to use where/set/on/and/or/groupBy/orderBy(enum) and your model has multiple fields of a single enum type.
+
+**0.7.6** *released 2011-12-21*
+
+- Iciql now tries to instantiate a default value from an annotated default value IFF the field object is null, it is specified *nullable = false*, and a defaultValue exists. This only applies to *db.insert* or *db.update*.
+
+**0.7.5** *released 2011-12-12*
+
+- Iciql now identifies wildcard queries and builds a dynamic column lookup. Otherwise, the original field-position-based approach is used. This corrects the performance regression released in 0.7.4 while still fixing the wildcard statement column mapping problem.
+
+**0.7.4** *released 2011-12-06*
+
+- Disallow **declaring and explicitly referencing** multiple primitive booleans in a single model.<br/>A runtime exception will be thrown if an attempt to use where/set/on/and/or/groupBy/orderBy(boolean) and your model has multiple mapped primitive boolean fields.
+- Added list alternatives to the varargs methods because it was too easy to forget list.toArray()<br/>
+*Db.executeQuery(Class<? extends T> modelClass, String sql, List<?> args)*<br/>
+*Db.executeQuery(String sql, List<?> args)*<br/>
+*Query.where(String fragment, List<?> args)*<br/>
+- Fixed inherited JaQu bug related to model classes and wildcard queries (select *).<p/>
+Iciql maps resultset columns by the index of the model class field from a list. This assumes that *all* columns in the resultset have a corresponding model field definition. This works fine for most queries because iciql explicitly selects columns from the table (*select alpha, beta...*) when you execute *select()*. The problem is when iciql issues a dynamic wildcard query and your model does not represent all columns in the resultset: columns and fields may fail to correctly line-up.<p/>
+Iciql now maps all fields by their column name, not by their position.
+
+**0.7.3** *released 2011-12-06*
+
+- api change release (API v8)
+- Fixed JOIN ON primitives
+- Fixed GROUP BY primitives
+- Fixed primitive references when selecting into a custom type with primitives
+- Improved fluent/type-safety of joins
+
+**0.7.2** *released 2011-11-30*
+
+- generated models are now serializable with a default serial version id of 1
+- Updated to H2 1.3.162
+- Updated to HSQL 2.2.6 (100% unit test pass now that [this bug](https://sourceforge.net/tracker/?func=detail&aid=3390047&group_id=23316&atid=378131) was fixed)
+
+**0.7.1** *released 2011-08-31*
+
+- api change release (API v7)
+- Undeprecated interface configuration
+- Interface configuration now maps ALL fields, not just public fields
+- Added @IQIgnore annotation to explicitly skip fields for interface configuration
+- Created additional Define static methods to bring interface configuration to near-parity with annotation configuration
+- Documented POJO configuration option (limited subset of interface configuration)
+- Fix to PostgreSQL dialect when creating autoincrement columns
+- Fix to default dialect when creating autoincrement columns
+- Added Db.open(url) method
+
+**0.7.0** *released 2011-08-17*
+
+- api change release (API v6)
+- Finished MySQL dialect implementation. MySQL 5.0.51b passes 100% of tests.
+- Added PostgreSQL dialect. PostgreSQL 9.0 passes all but the boolean-as-int tests.
+- Added Db.dropTable(T) method
+- Overhauled test suite and included more database configurations.
+- Renamed StatementLogger to IciqlLogger
+- Added IciqlLogger.warn method
+- Added IciqlLogger.drop method
+
+**0.6.6** *released 2011-08-15*
+
+- api change release (API v5)
+- Disabled two concurrency unit tests since I believe they are flawed and do not yield reproducible results
+- Added Derby database dialect. Derby 10.7.1.1 and 10.8.1.2 pass 100% of tests.
+- Implemented HSQL MERGE syntax. HSQL 2.2.4 fails 1 test which is a known [bug in HSQL](https://sourceforge.net/tracker/?func=detail&aid=3390047&group_id=23316&atid=378131)
+- Updated to H2 1.3.159
+
+**0.6.5** *released 2011-08-12*
+
+- fixed failure of db.delete(PrimitiveModel) and db.update(PrimitiveModel)
+
+**0.6.4** *released 2011-08-12*
+
+- api change release (API v4)
+- @IQTable.createIfRequired -> @IQTable.create
+- don't INSERT primitive autoIncrement fields, let database assign value
+- full support for primitives in all clauses
+- DECIMAL(length, scale) support
+- unspecified length String fields are now CLOB instead of TEXT. dialects can intercept this and convert to another type. e.g. MySQL dialect can change CLOB to TEXT.
+- java.lang.Boolean now maps to BOOLEAN instead of BIT
+- expressions on unmapped fields will throw an IciqlException
+- expressions on unsupported types will throw an IciqlException
+- improved exception reporting by including generated statement, if available
+- moved dialects back to main package
+- improved automatic dialect determination on pooled connections
+- moved create table and create index statement generation into dialects
+- added HSQL dialect. HSQL fails 4 out of 50 unit tests.
+ - 2 failures are unimplemented merge
+ - 1 has been filed and accepted as a [bug in HSQL](https://sourceforge.net/tracker/?func=detail&aid=3390047&group_id=23316&atid=378131)
+ - 1 is a concurrency issue, but the test may be flawed
+- added untested MySQL dialect
+- renamed <b>_ iq_versions</b> table to *iq_versions* since leading _ character is troublesome for some databases.
+- @IQColumn(allowNull=true) -> @IQColumn(nullable=true)
+- All **Object** columns are assumed NULLABLE unless explicitly set *@IQColumn(nullable = false)*
+- All **Primitive** columns are assumed NOT NULLABLE unless explicitly set *@IQColumn(nullable = true)*
+- allow using objects to assign default values<br/>
+%BEGINCODE%
+// CREATE TABLE ... myDate DATETIME DEFAULT '2000-02-01 00:00:00'
+@IQColumn
+Date myDate = new Date(100, 1, 1);
+%ENDCODE%
+- changed @IQTable.primaryKey definition to use array of column names<br/>
+%BEGINCODE%
+@IQTable( primaryKey = {"name", "nickname"})
+%ENDCODE%
+
+**0.6.3** *released 2011-08-08*
+
+- api change release (API v3)
+- finished enum support (issue 4)
+- added UUID type support (H2 databases only)
+- added partial primitives support *(primitives may not be used for compile-time condition clauses)*
+- added *between(A y).and(A z)* condition syntax
+- moved dialects into separate package
+
+**0.6.2** *released 2011-08-05*
+
+- api change release (API v2)
+- fix to versioning to support H2 1.3.158+
+- added BLOB support (issue 1)
+- added java.lang.Enum support (issue 2)
+- allow runtime flexible mapping of BOOL columns to Integer fields
+- allow runtime flexible mapping of INT columns to Boolean fields
+- annotations overhaul to reduce verbosity
+ - @IQSchema(name="public") -> @IQSchema("public")
+ - @IQDatabase(version=2) -> @IQVersion(2)
+ - @IQTable(version=2) -> @IQVersion(2)
+ - @IQIndex annotation simplified to be used for one index definition and expanded to specify index name
+ - added @IQIndexes annotation to specify multiple IQIndex annotations<br/>
+%BEGINCODE%
+@IQIndexes({ @IQIndex("name"), @IQIndex(name="myindexname" value={"name", "nickname"}) })
+%ENDCODE%
+ - @IQColumn(maxLength=20) -> @IQColumn(length=20)
+ - @IQColumn(trimString=true) -> @IQColumn(trim=true)
+
+**0.5.0** *released 2011-08-03*
+
+- initial release (API v1)
+
+*API changes compared to JaQu from H2 1.3.157 sources*
+
+- deprecated model class interface configuration
+- added *Db.open(Connection conn)* method, changed constructor to default scope
+- added *Db.registerDialect* static methods to register custom dialects
+- added *Query.where(String fragment, Object... args)* method to build a runtime query fragment when compile-time queries are too strict
+- added *Db.executeQuery(String query, Object... args)* to execute a complete sql query with optional arguments
+- added *Db.executeQuery(Class modelClass, String query, Object... args)* to execute a complete sql query, with optional arguments, and build objects from the result
+- added *Db.buildObjects(Class modelClass, ResultSet rs)* method to build objects from the ResultSet of a plain sql query
+- added *ThreadLocal<T> com.iciql.Utils.newThreadLocal(final Class<? extends T> clazz)* method
+- added optional console statement logger and SLF4J statement logger
+- refactored dialect support
+- throw *IciqlException* (which is a RuntimeException) instead of RuntimeException
+- synchronized *Db.classMap* for concurrent sharing of a Db instance
+- Database/table versioning uses the <b>_iq_versions </b> table, the <b>_ jq_versions</b> table, if present, is ignored
+- Changed the following class names:
+ - org.h2.jaqu.Table => com.iciql.Iciql
+ - org.h2.jaqu.JQSchema => com.iciql.IQSchema
+ - org.h2.jaqu.JQDatabase => com.iciql.IQDatabase
+ - org.h2.jaqu.JQIndex => com.iciql.IQIndex
+ - org.h2.jaqu.JQTable => com.iciql.IQTable
+ - org.h2.jaqu.JQColumn => com.iciql.IQColumn
+- Changed the following method names:
+ - org.h2.jaqu.Table.define() => com.iciql.Iciql.defineIQ()
+ - QueryConditon.bigger => QueryCondition.exceeds
+ - QueryConditon.biggerEqual => QueryCondition.atLeast
+ - QueryConditon.smaller => QueryCondition.lessThan
+ - QueryConditon.smallEqual => QueryCondition.atMost
diff --git a/src/site/06_jaqu_comparison.mkd b/src/site/06_jaqu_comparison.mkd new file mode 100644 index 0000000..20df5d5 --- /dev/null +++ b/src/site/06_jaqu_comparison.mkd @@ -0,0 +1,31 @@ +
+## Comparison to JaQu
+
+This is an overview of the fundamental differences between the original JaQu project and the current featureset of iciql.
+
+<table class="table">
+<tr><th></th><th>Iciql</th><th>JaQu</th></tr>
+<tr><th colspan="3">core</th></tr>
+<tr><td>deployment</td><td>small, discrete library</td><td>depends on H2 database jar file</td></tr>
+<tr><td>databases</td><td>H2, HSQL, Derby, MySQL, and PostreSQL</td><td>H2 only</td></tr>
+<tr><td>logging</td><td>console, SLF4J, or custom logging</td><td>console logging</td></tr>
+<tr><td>exceptions</td><td>always includes generated statement in exception, when available</td><td>--</td></tr>
+<tr><td>column mappings</td><td>wildcard queries index result sets by column name</td><td>all result sets built by field index<br/>this can fail for wildcard queries</td></tr>
+<tr><td>savepoints</td><td>bulk operations (insert, update, delete) use savepoints with rollback in the event of failure</td><td>--</td></tr>
+<tr><th colspan="3">syntax and api</th></tr>
+<tr><td>VIEWs</td><td>create readonly views either from a class definition or from a fluent statement</td><td>--</td></tr>
+<tr><td>dynamic queries</td><td>methods and where clauses for dynamic queries that build iciql objects</td><td>--</td></tr>
+<tr><td>DROP</td><td>syntax to drop a table or view</td><td></td></tr>
+<tr><td>BETWEEN</td><td>syntax for specifying a BETWEEN x AND y clause</td><td>--</td></tr>
+<tr><th colspan="3">types</th></tr>
+<tr><td>primitives</td><td>fully supported</td><td>--</td></tr>
+<tr><td>enums</td><td>fully supported</td><td>--</td></tr>
+<tr><td>DECIMAL(length,scale)</td><td>can specify length/precision and scale</td><td>--</td></tr>
+<tr><td>BOOLEAN</td><td>flexible mapping of boolean as bool, varchar, or int</td><td>--</td></tr>
+<tr><td>BLOB</td><td>partially supported <em>(can not be used in a WHERE clause)</em></td><td>--</td></tr>
+<tr><td>UUID</td><td>fully supported <em>(H2 only)</em> </td><td>--</td></tr>
+<tr><th colspan="3">configuration</th></tr>
+<tr><td>DEFAULT values</td><td>set from annotation, <em>default object values</em>, or Define.defaultValue()</td><td>set from annotations</td></tr>
+<tr><td>Interface Configuration<br/>Mapped Fields</td><td><em>all fields</em> are mapped regardless of scope<br/>fields are ignored by annotating with @IQIgnore</td><td><em>all public fields</em> are mapped<br/>fields are ignored by reducing their scope</td></tr>
+<tr><td>Index names</td><td>can be set</td><td>--</td></tr>
+</table>
\ No newline at end of file diff --git a/src/site/custom.less b/src/site/custom.less new file mode 100644 index 0000000..31098f5 --- /dev/null +++ b/src/site/custom.less @@ -0,0 +1,40 @@ +
+// GLOBAL VALUES
+// --------------------------------------------------
+@standardGray: #ccc;
+@cornflower: #abd4ff;
+@white: #fff;
+
+// Dropdown
+// -------------------------
+@dropdownLinkBackgroundHover: @cornflower;
+
+// Navbar
+// -------------------------
+@navbarHeight: 55px;
+@navbarBackground: @cornflower;
+@navbarBackgroundHighlight: @cornflower;
+@navbarText: @white;
+@navbarLinkColor: @white;
+@navbarLinkColorHover: @white;
+@navbarLinkColorActive: @white;
+@navbarLinkBackgroundHover: transparent;
+@navbarLinkBackgroundActive: transparent;
+
+.navbar {
+ .brand {
+ @elementHeight: 48px;
+ padding: 7px;
+ }
+}
+
+.navbar .nav > li > a {
+ font-size: @baseFontSize + 2;
+ text-shadow: 0 1px 0 #6b94df;
+}
+
+body { padding-top: @navbarHeight + 15 } /* 60px to make the container go all the way to the bottom of the topbar */
+footer { margin-top: 25px; padding: 15px 0 16px; border-top: 1px solid #E5E5E5; }
+
+a:hover { text-decoration: underline !important; }
+em { color: #50a000; }
diff --git a/src/site/resources/.gitignore b/src/site/resources/.gitignore new file mode 100644 index 0000000..1277f62 --- /dev/null +++ b/src/site/resources/.gitignore @@ -0,0 +1,2 @@ +/site_analytics.html +/site_ads.html diff --git a/src/site/resources/iciql-favicon.png b/src/site/resources/iciql-favicon.png Binary files differnew file mode 100644 index 0000000..dda916b --- /dev/null +++ b/src/site/resources/iciql-favicon.png diff --git a/src/site/resources/iciql.png b/src/site/resources/iciql.png Binary files differnew file mode 100644 index 0000000..aa1da69 --- /dev/null +++ b/src/site/resources/iciql.png diff --git a/src/site/resources/iciql.xcf b/src/site/resources/iciql.xcf Binary files differnew file mode 100644 index 0000000..1f9f501 --- /dev/null +++ b/src/site/resources/iciql.xcf diff --git a/src/site/resources/iciql2.png b/src/site/resources/iciql2.png Binary files differnew file mode 100644 index 0000000..9e96ae5 --- /dev/null +++ b/src/site/resources/iciql2.png diff --git a/src/site/resources/iciql2.xcf b/src/site/resources/iciql2.xcf Binary files differnew file mode 100644 index 0000000..c07a46b --- /dev/null +++ b/src/site/resources/iciql2.xcf diff --git a/src/site/resources/iciql_white.png b/src/site/resources/iciql_white.png Binary files differnew file mode 100644 index 0000000..4a97147 --- /dev/null +++ b/src/site/resources/iciql_white.png diff --git a/src/site/resources/javadoc.css b/src/site/resources/javadoc.css new file mode 100644 index 0000000..8a8b972 --- /dev/null +++ b/src/site/resources/javadoc.css @@ -0,0 +1,52 @@ +/* Javadoc style sheet */
+
+/* Define colors, fonts and other style attributes here to override the defaults */
+
+/* Page background color */
+body { font-size:13px; background-color: #FFFFFF; color:#000000 }
+
+hr {
+ color: #ffffff;
+ background-color: #ffffff;
+ height: 1px; !important
+}
+
+/* Headings */
+h1 { font-size: 1.5em }
+h2 { font-size: 1.5em }
+
+table {
+ border: 1px solid #ccc; !important
+}
+
+table th {
+ border: 0px solid #ccc; !important
+ font-size: 1.0em; !important
+}
+
+table th font {
+ font-size: 1.3em; !important
+}
+
+table td {
+ border: 0px solid; !important
+}
+
+/* Table colors */
+.TableHeadingColor { background-color: #f0f0f0; } /* light gray */
+.TableSubHeadingColor { background-color: #f0f0f0; } /* light gray */
+.TableRowColor { }
+
+/* Font used in left-hand frame lists */
+.FrameTitleFont { }
+.FrameHeadingFont { }
+.FrameItemFont { }
+
+/* Navigation bar fonts and colors */
+.NavBarCell1 { background-color:#f0f0f0; } /* light gray */
+.NavBarCell1Rev { background-color:#00008B; color:#ffffff} /* Dark Blue */
+.NavBarFont1 { }
+.NavBarFont1Rev { color:#ffffff;}
+
+.NavBarCell2 { }
+.NavBarCell3 { }
\ No newline at end of file diff --git a/src/test/java/com/iciql/test/AliasMapTest.java b/src/test/java/com/iciql/test/AliasMapTest.java new file mode 100644 index 0000000..092f38b --- /dev/null +++ b/src/test/java/com/iciql/test/AliasMapTest.java @@ -0,0 +1,139 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.IciqlException; +import com.iciql.test.models.PrimitivesModel; +import com.iciql.test.models.Product; +import com.iciql.util.Utils; + +/** + * Tests object and primitive alias referencing. + */ +public class AliasMapTest { + + /** + * Tests that columns (p.unitsInStock) are not compared by value with the + * value (9), but by reference (using an identity hash map). See + * http://code.google.com/p/h2database/issues/detail?id=119 + * + * @author d moebius at scoop dash gmbh dot de + */ + @Test + public void testObjectAliasMapping() throws Exception { + Db db = IciqlSuite.openNewDb(); + db.insertAll(Product.getList()); + + // baseline count is the next id value + long bc = Utils.COUNTER.get(); + // number of fields in primitives model class + // each from() call will increment Utils.COUNTER by this amount + int fc = Product.class.getFields().length; + + Product p = new Product(); + // This test confirms standard object referencing querying. + long count = db.from(p).where(p.productId).is(9).selectCount(); + assertEquals(1, count); + // Confirms that productId counter value is baseline counter value + assertEquals(bc, p.productId.intValue()); + try { + // This test compares "bc + fc" which is the counter value of + // unitsInStock assigned by Utils.newObject() after the 2nd pass + // through from(). + // + // Object fields map by REFERENCE, not value. + db.from(p).where(Long.valueOf(bc + fc).intValue()).is(9).orderBy(p.productId).select(); + assertTrue("Fail: object field is mapping by value.", false); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode()); + assertEquals(bc + 5, p.productId.intValue()); + } + + try { + // This test compares Integer(bc) which is the counter value of + // unitsInStock assigned by Utils.newObject() after the 3rd pass + // through from(). + // + // Object fields map by REFERENCE, not value. + db.from(p).where(Long.valueOf(bc).intValue()).is(9).orderBy(p.productId).select(); + assertTrue("Fail: object field is mapping by value.", false); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode()); + assertEquals(bc + (2 * fc), p.productId.intValue()); + } + + db.close(); + } + + /** + * Confirms that primitive aliases ARE mapped by value. + */ + @Test + public void testPrimitiveAliasMapping() throws Exception { + Db db = IciqlSuite.openNewDb(); + PrimitivesModel model = new PrimitivesModel(); + model.myLong = 100L; + db.insert(model); + model.myLong = 200L; + db.insert(model); + + // baseline count is the next id value + long bc = Utils.COUNTER.get(); + // number of fields in primitives model class + // each from() call will increment Utils.COUNTER by this amount + int fc = PrimitivesModel.class.getFields().length; + + PrimitivesModel p = new PrimitivesModel(); + // This test confirms standard primitive referencing querying. + long count = db.from(p).where(p.myLong).is(100L).selectCount(); + assertEquals(1, count); + // Confirms that myLong counter value is bc + assertEquals(bc, p.myLong); + try { + // This test compares "bc + fc" which is the counter value + // of myLong assigned by Utils.newObject() after the 2nd pass + // through from(). + // + // Primitive fields map by VALUE. + count = db.from(p).where(bc + fc).is(100L).selectCount(); + assertEquals(1, count); + assertEquals(bc + fc, p.myLong); + } catch (IciqlException e) { + assertTrue(e.getMessage(), false); + } + try { + // This test compares "bc" which was the counter value of + // myLong assigned by Utils.newObject() after the 1st pass + // through from(). "bc" is unmapped now and will throw an + // exception. + // + // Primitive fields map by VALUE. + db.from(p).where(bc).is(100L).select(); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode()); + assertEquals(bc + (2 * fc), p.myLong); + } + db.close(); + } +}
\ No newline at end of file diff --git a/src/test/java/com/iciql/test/AnnotationsTest.java b/src/test/java/com/iciql/test/AnnotationsTest.java new file mode 100644 index 0000000..6aa75ad --- /dev/null +++ b/src/test/java/com/iciql/test/AnnotationsTest.java @@ -0,0 +1,196 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.IciqlException; +import com.iciql.test.models.Product; +import com.iciql.test.models.ProductAnnotationOnly; +import com.iciql.test.models.ProductInheritedAnnotation; +import com.iciql.test.models.ProductMixedAnnotation; +import com.iciql.test.models.ProductNoCreateTable; +import com.iciql.util.Utils; + +/** + * Test annotation processing. + */ +public class AnnotationsTest { + + /** + * This object represents a database (actually a connection to the + * database). + */ + + private Db db; + + @Before + public void setUp() { + db = IciqlSuite.openNewDb(); + db.insertAll(Product.getList()); + db.insertAll(ProductAnnotationOnly.getList()); + db.insertAll(ProductMixedAnnotation.getList()); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testIndexCreation() throws SQLException { + // test indexes are created, and columns are in the right order + DatabaseMetaData meta = db.getConnection().getMetaData(); + String schema = IciqlSuite.getDefaultSchema(db); + boolean toUpper = meta.storesUpperCaseIdentifiers(); + boolean toLower = meta.storesLowerCaseIdentifiers(); + ResultSet rs = meta.getIndexInfo(null, prepName(schema, toUpper, toLower), + prepName("ANNOTATEDPRODUCT", toUpper, toLower), false, true); + + List<String> list = Utils.newArrayList(); + while (rs.next()) { + String col = rs.getString("COLUMN_NAME"); + String index = rs.getString("INDEX_NAME"); + list.add((col + ":" + index).toLowerCase()); + } + assertTrue(list.contains("name:annotatedproduct_idx_0")); + assertTrue(list.contains("cat:annotatedproduct_idx_0")); + assertTrue(list.contains("name:nameidx")); + } + + private String prepName(String name, boolean upper, boolean lower) { + if (name == null) { + return null; + } + if (upper) { + return name.toUpperCase(); + } else if (lower) { + return name.toLowerCase(); + } + return name; + } + + @Test + public void testProductAnnotationOnly() { + ProductAnnotationOnly p = new ProductAnnotationOnly(); + assertEquals(10, db.from(p).selectCount()); + + // test IQColumn.name="cat" + assertEquals(2, db.from(p).where(p.category).is("Beverages").selectCount()); + + // test IQTable.annotationsOnly=true + // public String unmappedField is ignored by iciql + try { + db.from(p).where(p.unmappedField).is("unmapped").selectCount(); + assertTrue("this should never execute", false); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode()); + } + + // 10 objects, 10 autoIncremented unique values + assertEquals(10, db.from(p).selectDistinct(p.productName).size()); + + // test IQTable.primaryKey=id + try { + db.insertAll(ProductAnnotationOnly.getList()); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_DUPLICATE_KEY, e.getIciqlCode()); + } + } + + @Test + public void testProductMixedAnnotation() { + ProductMixedAnnotation p = new ProductMixedAnnotation(); + + // test IQColumn.name="cat" + assertEquals(2, db.from(p).where(p.category).is("Beverages").selectCount()); + + // test IQTable.annotationsOnly=false + // public String mappedField is reflectively mapped by iciql + assertEquals(10, db.from(p).where(p.mappedField).is("mapped").selectCount()); + + // test IQIgnore annotation + assertEquals(null, db.from(p).selectFirst().productDescription); + + // test IQColumn.primaryKey=true + try { + db.insertAll(ProductMixedAnnotation.getList()); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_DUPLICATE_KEY, e.getIciqlCode()); + } + } + + @Test + public void testTrimStringAnnotation() { + ProductAnnotationOnly p = new ProductAnnotationOnly(); + ProductAnnotationOnly prod = db.from(p).selectFirst(); + String oldValue = prod.category; + String newValue = "01234567890123456789"; + // 2 chars exceeds field max + prod.category = newValue; + db.update(prod); + + ProductAnnotationOnly newProd = db.from(p).where(p.productId).is(prod.productId).selectFirst(); + assertEquals(newValue.substring(0, 15), newProd.category); + + newProd.category = oldValue; + db.update(newProd); + } + + @Test + public void testColumnInheritanceAnnotation() { + ProductInheritedAnnotation table = new ProductInheritedAnnotation(); + List<ProductInheritedAnnotation> inserted = ProductInheritedAnnotation.getData(); + db.insertAll(inserted); + + List<ProductInheritedAnnotation> retrieved = db.from(table).select(); + + for (int j = 0; j < retrieved.size(); j++) { + ProductInheritedAnnotation i = inserted.get(j); + ProductInheritedAnnotation r = retrieved.get(j); + assertEquals(i.category, r.category); + assertEquals(i.mappedField, r.mappedField); + assertEquals(i.unitsInStock, r.unitsInStock); + assertEquals(i.unitPrice, r.unitPrice); + assertEquals(i.name(), r.name()); + assertEquals(i.id(), r.id()); + } + } + + @Test + public void testCreateTableIfRequiredAnnotation() { + // tests IQTable.createTableIfRequired=false + try { + db.insertAll(ProductNoCreateTable.getList()); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_OBJECT_NOT_FOUND, e.getIciqlCode()); + } + } + +} diff --git a/src/test/java/com/iciql/test/BooleanModelTest.java b/src/test/java/com/iciql/test/BooleanModelTest.java new file mode 100644 index 0000000..1e1630a --- /dev/null +++ b/src/test/java/com/iciql/test/BooleanModelTest.java @@ -0,0 +1,128 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.test.models.BooleanModel;
+import com.iciql.test.models.BooleanModel.BooleanAsIntModel;
+
+/**
+ * Tests interchangeable mapping of INT columns with Booleans and BOOL columns
+ * with Integers.
+ * <ul>
+ * <li>mapping a BIT/BOOLEAN column as an Integer
+ * <li>mapping a INT column as a Boolean.
+ * </ul>
+ */
+public class BooleanModelTest {
+
+ @Test
+ public void testBooleanColumn() {
+ Db db = IciqlSuite.openNewDb();
+ db.insertAll(BooleanModel.getList());
+ BooleanAsIntModel b = new BooleanAsIntModel();
+ List<BooleanAsIntModel> models = db.from(b).select();
+ int count = 0;
+ for (BooleanAsIntModel model : models) {
+ if ((model.id % 2) == 1) {
+ // assert that odd ids are true
+ assertTrue(model.mybool > 0);
+ } else {
+ // assert that even ids are false
+ assertTrue(model.mybool == 0);
+ }
+
+ // count true values
+ if (model.mybool > 0) {
+ count++;
+ }
+ }
+ assertEquals(2, count);
+
+ // invert boolean values and update
+ for (BooleanAsIntModel model : models) {
+ model.mybool = model.mybool > 0 ? 0 : 1;
+ }
+ db.updateAll(models);
+
+ // check even ids are true
+ models = db.from(b).select();
+ for (BooleanAsIntModel model : models) {
+ if ((model.id % 2) == 1) {
+ // assert that odd ids are false
+ assertTrue(model.mybool == 0);
+ } else {
+ // assert that even ids are true
+ assertTrue(model.mybool > 0);
+ }
+ }
+ db.close();
+ }
+
+ @Test
+ public void testIntColumn() {
+ Db db = IciqlSuite.openNewDb();
+ // insert INT column
+ db.insertAll(BooleanAsIntModel.getList());
+
+ // select all rows with INT column and map to Boolean
+ BooleanModel b = new BooleanModel();
+ List<BooleanModel> models = db.from(b).select();
+ int count = 0;
+ for (BooleanModel model : models) {
+ if ((model.id % 2) == 1) {
+ // assert that odd ids are true
+ assertTrue(model.mybool);
+ } else {
+ // assert that even ids are false
+ assertTrue(!model.mybool);
+ }
+
+ // count true values
+ if (model.mybool) {
+ count++;
+ }
+ }
+ assertEquals(2, count);
+
+ // invert boolean values and update
+ for (BooleanModel model : models) {
+ model.mybool = !model.mybool;
+ }
+ db.updateAll(models);
+
+ // check even ids are true
+ models = db.from(b).select();
+ for (BooleanModel model : models) {
+ if ((model.id % 2) == 1) {
+ // assert that odd ids are false
+ assertTrue(!model.mybool);
+ } else {
+ // assert that even ids are true
+ assertTrue(model.mybool);
+ }
+ }
+ db.close();
+ }
+}
diff --git a/src/test/java/com/iciql/test/ClobTest.java b/src/test/java/com/iciql/test/ClobTest.java new file mode 100644 index 0000000..49cee72 --- /dev/null +++ b/src/test/java/com/iciql/test/ClobTest.java @@ -0,0 +1,115 @@ +/* + * 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.test; + +import static com.iciql.Define.primaryKey; +import static com.iciql.Define.tableName; +import static org.junit.Assert.assertEquals; + +import java.text.MessageFormat; +import java.util.Arrays; +import java.util.List; + +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.Iciql; + +/** + * Tests if converting a CLOB to a String works. + */ +public class ClobTest { + + @Test + public void testClob() throws Exception { + String create = "CREATE TABLE CLOB_TEST(ID INT PRIMARY KEY, WORDS {0})"; + Db db = IciqlSuite.openNewDb(); + db.executeUpdate(MessageFormat.format(create, "VARCHAR(255)")); + db.insertAll(StringRecord.getList()); + testSimpleUpdate(db, "VARCHAR fail"); + db.executeUpdate("DROP TABLE CLOB_TEST"); + db.close(); + + db = IciqlSuite.openNewDb(); + db.executeUpdate(MessageFormat.format(create, db.getDialect().convertSqlType("CLOB"))); + db.insertAll(StringRecord.getList()); + testSimpleUpdate(db, "CLOB fail because of single quote artifacts"); + db.executeUpdate("DROP TABLE CLOB_TEST"); + db.close(); + } + + private void testSimpleUpdate(Db db, String failureMsg) { + String newWords = "I changed the words"; + StringRecord r = new StringRecord(); + StringRecord originalRecord = db.from(r).where(r.id).is(2).selectFirst(); + String oldWords = originalRecord.words; + originalRecord.words = newWords; + db.update(originalRecord); + + StringRecord r2 = new StringRecord(); + StringRecord revisedRecord = db.from(r2).where(r2.id).is(2).selectFirst(); + assertEquals(failureMsg, newWords, revisedRecord.words); + + // undo update + originalRecord.words = oldWords; + db.update(originalRecord); + } + + /** + * A simple class used in this test. + */ + public static class StringRecord implements Iciql { + + public Integer id; + public String words; + + public StringRecord() { + // public constructor + } + + private StringRecord(int id, String words) { + this.id = id; + this.words = words; + } + + public void defineIQ() { + tableName("CLOB_TEST"); + primaryKey(id); + } + + private static StringRecord create(int id, String words) { + return new StringRecord(id, words); + } + + public static List<StringRecord> getList() { + StringRecord[] list = { + create(1, "Once upon a midnight dreary, while I pondered weak and weary,"), + create(2, "Over many a quaint and curious volume of forgotten lore,"), + create(3, "While I nodded, nearly napping, suddenly there came a tapping,"), + create(4, "As of some one gently rapping, rapping at my chamber door."), + create(5, "`'Tis some visitor,' I muttered, `tapping at my chamber door -"), + create(6, "Only this, and nothing more.'") }; + + return Arrays.asList(list); + } + + public String toString() { + return id + ": " + words; + } + } +} diff --git a/src/test/java/com/iciql/test/ConcurrencyTest.java b/src/test/java/com/iciql/test/ConcurrencyTest.java new file mode 100644 index 0000000..e248265 --- /dev/null +++ b/src/test/java/com/iciql/test/ConcurrencyTest.java @@ -0,0 +1,199 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; + +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.IciqlException; +import com.iciql.Query; +import com.iciql.test.models.Product; +import com.iciql.util.Utils; + +/** + * Tests concurrency and alias instance sharing. + */ +public class ConcurrencyTest { + + private int numberOfTests = 800; + + @Before + public void setUp() { + Db db = IciqlSuite.openNewDb(); + db.insertAll(Product.getList()); + } + + @Test + public void testAliasSharing() throws Exception { + Db db = IciqlSuite.openCurrentDb(); + try { + // Single-threaded example of why aliases can NOT be shared. + Product p = new Product(); + Query<Product> query1 = db.from(p); + Query<Product> query2 = db.from(p); + + // if you could share alias instances both counts should be equal + long count1 = 0; + try { + count1 = query1.where(p.category).is("Beverages").selectCount(); + } catch (IciqlException e) { + assertEquals(IciqlException.CODE_UNMAPPED_FIELD, e.getIciqlCode()); + } + long count2 = query2.where(p.category).is("Beverages").selectCount(); + + // but they aren't + assertEquals(0, count1); + assertEquals(2, count2); + assertTrue(count1 != count2); + } finally { + db.close(); + } + } + + @Test + @Ignore + public void testConcurrencyFinal() throws Exception { + // Multi-threaded example of why aliases can NOT be shared. + // + // This test looks like it _could_ work and you may find that it _can_ + // work, but you should also find that it _will_ fail. + + List<Thread> threads = Utils.newArrayList(); + final AtomicInteger failures = new AtomicInteger(0); + final Product p = new Product(); + for (int i = 0; i < numberOfTests; i++) { + final int testNumber = i; + Thread t = new Thread(new Runnable() { + public void run() { + try { + int testCase = testNumber % 10; + test(testCase, p); + } catch (AssertionError e) { + failures.incrementAndGet(); + } catch (IciqlException e) { + failures.incrementAndGet(); + if (e.getIciqlCode() != IciqlException.CODE_UNMAPPED_FIELD) { + System.err.println("UNEXPECTED ERROR in testConcurrencyFinal()"); + e.printStackTrace(); + } + } + } + }, "ICIQL-" + i); + t.start(); + threads.add(t); + } + + // wait till all threads complete + for (Thread t : threads) { + t.join(); + } + + assertTrue("This should fail. Try running a few more times.", failures.get() > 0); + } + + @Test + @Ignore + public void testConcurrencyThreadLocal() throws Exception { + List<Thread> threads = Utils.newArrayList(); + final AtomicInteger failures = new AtomicInteger(0); + final ThreadLocal<Product> tl = Utils.newThreadLocal(Product.class); + for (int i = 0; i < numberOfTests; i++) { + final int testNumber = i; + Thread t = new Thread(new Runnable() { + public void run() { + try { + int testCase = testNumber % 10; + test(testCase, tl.get()); + } catch (AssertionError e) { + failures.incrementAndGet(); + } catch (IciqlException e) { + failures.incrementAndGet(); + if (e.getIciqlCode() != IciqlException.CODE_UNMAPPED_FIELD) { + System.err.println("UNEXPECTED ERROR in testConcurrencyThreadLocal()"); + e.printStackTrace(); + } + } + } + }, "ICIQL-" + i); + t.start(); + threads.add(t); + } + + // wait till all threads complete + for (Thread t : threads) { + t.join(); + } + + assertEquals("ThreadLocal should never fail!", 0, failures.get()); + } + + private void test(int testCase, Product p) throws AssertionError { + Db db = IciqlSuite.openCurrentDb(); + try { + List<Product> list; + switch (testCase) { + case 0: + list = db.from(p).where(p.productName).is("Chai").select(); + assertEquals(1, list.size()); + assertEquals("Chai", list.get(0).productName); + break; + case 1: + list = db.from(p).where(p.category).is("Condiments").select(); + assertEquals(5, list.size()); + break; + case 3: + list = db.from(p).where(p.productName).is("Aniseed Syrup").select(); + assertEquals(1, list.size()); + assertEquals("Aniseed Syrup", list.get(0).productName); + break; + case 4: + list = db.from(p).where(p.productName).like("Chef%").select(); + assertEquals(2, list.size()); + assertTrue(list.get(0).productName.startsWith("Chef")); + assertTrue(list.get(1).productName.startsWith("Chef")); + break; + case 6: + list = db.from(p).where(p.unitsInStock).exceeds(0).select(); + assertEquals(9, list.size()); + break; + case 7: + list = db.from(p).where(p.unitsInStock).is(0).select(); + assertEquals(1, list.size()); + assertEquals("Chef Anton's Gumbo Mix", list.get(0).productName); + break; + case 9: + list = db.from(p).where(p.productId).is(7).select(); + assertEquals(1, list.size()); + assertTrue(7 == list.get(0).productId); + break; + default: + list = db.from(p).select(); + assertEquals(10, list.size()); + } + } finally { + db.close(); + } + } +} diff --git a/src/test/java/com/iciql/test/DefaultValuesTest.java b/src/test/java/com/iciql/test/DefaultValuesTest.java new file mode 100644 index 0000000..1374379 --- /dev/null +++ b/src/test/java/com/iciql/test/DefaultValuesTest.java @@ -0,0 +1,61 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.DbInspector;
+import com.iciql.ValidationRemark;
+import com.iciql.test.models.DefaultValuesModel;
+
+/**
+ * Tests default object values.
+ */
+public class DefaultValuesTest {
+
+ @Test
+ public void testDefaultObjectValues() {
+ Db db = IciqlSuite.openNewDb();
+
+ // insert random model
+ DefaultValuesModel model = new DefaultValuesModel();
+ db.insert(model);
+
+ DefaultValuesModel v = new DefaultValuesModel();
+
+ // retrieve model and compare
+ DefaultValuesModel retrievedModel = db.from(v).selectFirst();
+ assertTrue(model.myInteger.equals(retrievedModel.myInteger));
+ assertTrue(model.myDate.equals(retrievedModel.myDate));
+ assertTrue(model.myEnumIdTree.equals(retrievedModel.myEnumIdTree));
+ assertTrue(model.myNameTree.equals(retrievedModel.myNameTree));
+ assertTrue(model.myOrdinalTree.equals(retrievedModel.myOrdinalTree));
+ assertTrue(retrievedModel.myNullTree == null);
+
+ DbInspector inspector = new DbInspector(db);
+ List<ValidationRemark> remarks = inspector.validateModel(model, false);
+ db.close();
+ for (ValidationRemark remark : remarks) {
+ System.out.println(remark.toString());
+ }
+ }
+}
diff --git a/src/test/java/com/iciql/test/EnumsTest.java b/src/test/java/com/iciql/test/EnumsTest.java new file mode 100644 index 0000000..d8a0589 --- /dev/null +++ b/src/test/java/com/iciql/test/EnumsTest.java @@ -0,0 +1,129 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.IciqlException;
+import com.iciql.test.models.EnumModels;
+import com.iciql.test.models.EnumModels.EnumIdModel;
+import com.iciql.test.models.EnumModels.EnumOrdinalModel;
+import com.iciql.test.models.EnumModels.EnumStringModel;
+import com.iciql.test.models.EnumModels.Tree;
+
+/**
+ * Tests enum support.
+ */
+public class EnumsTest {
+
+ private Db db;
+
+ @Before
+ public void setUp() {
+ db = IciqlSuite.openNewDb();
+ db.insertAll(EnumIdModel.createList());
+ db.insertAll(EnumOrdinalModel.createList());
+ db.insertAll(EnumStringModel.createList());
+ }
+
+ @After
+ public void tearDown() {
+ db.close();
+ }
+
+ @Test
+ public void testEnumQueries() {
+ testIntEnums(new EnumIdModel());
+ testIntEnums(new EnumOrdinalModel());
+ testStringEnums(new EnumStringModel());
+ }
+
+ private void testIntEnums(EnumModels e) {
+ // ensure all records inserted
+ long count = db.from(e).selectCount();
+ assertEquals(5, count);
+
+ // 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.
+ EnumModels firstEnumValue = db.from(e).where(e.tree()).is(Tree.PINE).selectFirst();
+ assertEquals(Tree.PINE, firstEnumValue.tree());
+
+ EnumModels model = db.from(e).where(e.tree()).is(Tree.WALNUT).selectFirst();
+
+ assertEquals(400, model.id.intValue());
+ assertEquals(Tree.WALNUT, model.tree());
+
+ List<EnumModels> list = db.from(e).where(e.tree()).atLeast(Tree.BIRCH).select();
+ assertEquals(3, list.size());
+
+ // between is an int compare
+ list = db.from(e).where(e.tree()).between(Tree.BIRCH).and(Tree.WALNUT).select();
+ assertEquals(2, list.size());
+
+ }
+
+ private void testStringEnums(EnumModels e) {
+ // ensure all records inserted
+ long count = db.from(e).selectCount();
+ assertEquals(5, count);
+
+ // 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.
+ EnumModels firstEnumValue = db.from(e).where(e.tree()).is(Tree.PINE).selectFirst();
+ assertEquals(Tree.PINE, firstEnumValue.tree());
+
+ EnumModels model = db.from(e).where(e.tree()).is(Tree.WALNUT).selectFirst();
+
+ assertEquals(400, model.id.intValue());
+ assertEquals(Tree.WALNUT, model.tree());
+
+ List<EnumModels> list = db.from(e).where(e.tree()).isNot(Tree.BIRCH).select();
+ assertEquals(count - 1, list.size());
+
+ // between is a string compare
+ list = db.from(e).where(e.tree()).between(Tree.MAPLE).and(Tree.PINE).select();
+ assertEquals(3, list.size());
+ }
+
+ @Test
+ public void testMultipleEnumInstances() {
+ BadEnums b = new BadEnums();
+ try {
+ db.from(b).where(b.tree1).is(Tree.BIRCH).and (b.tree2).is(Tree.MAPLE).getSQL();
+ assertTrue("Failed to detect multiple Tree fields?!", false);
+ } catch (IciqlException e) {
+ assertTrue(e.getMessage(), e.getMessage().startsWith("Can not explicitly reference Tree"));
+ }
+ }
+
+ public static class BadEnums {
+ Tree tree1 = Tree.BIRCH;
+ Tree tree2 = Tree.MAPLE;
+ }
+}
diff --git a/src/test/java/com/iciql/test/ForeignKeyTest.java b/src/test/java/com/iciql/test/ForeignKeyTest.java new file mode 100644 index 0000000..6b4a3e7 --- /dev/null +++ b/src/test/java/com/iciql/test/ForeignKeyTest.java @@ -0,0 +1,81 @@ +/*
+ * Copyright 2012 Frédéric Gaillard.
+ * Copyright 2012 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.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.IciqlException;
+import com.iciql.test.models.CategoryAnnotationOnly;
+import com.iciql.test.models.ProductAnnotationOnlyWithForeignKey;
+
+/**
+ * Tests of Foreign Keys.
+ */
+public class ForeignKeyTest {
+
+ /**
+ * This object represents a database (actually a connection to the
+ * database).
+ */
+
+ private Db db;
+
+ @Before
+ public void setUp() {
+ db = IciqlSuite.openNewDb();
+ db.insertAll(CategoryAnnotationOnly.getList());
+ db.insertAll(ProductAnnotationOnlyWithForeignKey.getList());
+ }
+
+ @After
+ public void tearDown() {
+ db.dropTable(ProductAnnotationOnlyWithForeignKey.class);
+ db.dropTable(CategoryAnnotationOnly.class);
+ db.close();
+ }
+
+ @Test
+ public void testForeignKeyWithOnDeleteCascade() {
+ ProductAnnotationOnlyWithForeignKey p = new ProductAnnotationOnlyWithForeignKey();
+ long count1 = db.from(p).selectCount();
+
+ // should remove 2 associated products
+ CategoryAnnotationOnly c = new CategoryAnnotationOnly();
+ db.from(c).where(c.categoryId).is(1L).delete();
+
+ long count2 = db.from(p).selectCount();
+
+ assertEquals(count1, count2 + 2L);
+ }
+
+ @Test
+ public void testForeignKeyDropReferenceTable() {
+ try {
+ db.dropTable(CategoryAnnotationOnly.class);
+ assertTrue("Should not be able to drop reference table!", false);
+ } catch (IciqlException e) {
+ assertEquals(e.getMessage(), IciqlException.CODE_CONSTRAINT_VIOLATION, e.getIciqlCode());
+ }
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/IciqlSuite.java b/src/test/java/com/iciql/test/IciqlSuite.java new file mode 100644 index 0000000..a474404 --- /dev/null +++ b/src/test/java/com/iciql/test/IciqlSuite.java @@ -0,0 +1,614 @@ +/*
+ * Copyright 2011 James Moger.
+ * Copyright 2012 Frédéric Gaillard.
+ *
+ * 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.test;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.sql.SQLException;
+import java.text.DecimalFormat;
+import java.text.MessageFormat;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.dbcp.ConnectionFactory;
+import org.apache.commons.dbcp.DriverManagerConnectionFactory;
+import org.apache.commons.dbcp.PoolableConnectionFactory;
+import org.apache.commons.dbcp.PoolingDataSource;
+import org.apache.commons.pool.impl.GenericObjectPool;
+import org.hsqldb.persist.HsqlProperties;
+import org.junit.Assert;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.Result;
+import org.junit.runner.RunWith;
+import org.junit.runner.notification.Failure;
+import org.junit.runners.Suite;
+import org.junit.runners.Suite.SuiteClasses;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+import com.beust.jcommander.Parameters;
+import com.iciql.Constants;
+import com.iciql.Db;
+import com.iciql.test.models.BooleanModel;
+import com.iciql.test.models.CategoryAnnotationOnly;
+import com.iciql.test.models.ComplexObject;
+import com.iciql.test.models.Customer;
+import com.iciql.test.models.DefaultValuesModel;
+import com.iciql.test.models.EnumModels.EnumIdModel;
+import com.iciql.test.models.EnumModels.EnumOrdinalModel;
+import com.iciql.test.models.EnumModels.EnumStringModel;
+import com.iciql.test.models.MultipleBoolsModel;
+import com.iciql.test.models.Order;
+import com.iciql.test.models.PrimitivesModel;
+import com.iciql.test.models.Product;
+import com.iciql.test.models.ProductAnnotationOnly;
+import com.iciql.test.models.ProductAnnotationOnlyWithForeignKey;
+import com.iciql.test.models.ProductInheritedAnnotation;
+import com.iciql.test.models.ProductMixedAnnotation;
+import com.iciql.test.models.ProductView;
+import com.iciql.test.models.ProductViewFromQuery;
+import com.iciql.test.models.ProductViewInherited;
+import com.iciql.test.models.ProductViewInheritedComplex;
+import com.iciql.test.models.SupportedTypes;
+import com.iciql.util.IciqlLogger;
+import com.iciql.util.IciqlLogger.IciqlListener;
+import com.iciql.util.IciqlLogger.StatementType;
+import com.iciql.util.StringUtils;
+import com.iciql.util.Utils;
+
+/**
+ * JUnit 4 iciql test suite.
+ *
+ * By default this test suite will run against the H2 database. You can change
+ * this by switching the DEFAULT_TEST_DB value.
+ * <p>
+ * Alternatively, you can run this class an application which will run all tests
+ * for all tested database configurations.
+ * <p>
+ * NOTE: If you want to test against MySQL or PostgreSQL you must create an
+ * "iciql" database and allow user "sa" password "sa" complete control of that
+ * database.
+ *
+ */
+@RunWith(Suite.class)
+@SuiteClasses({ AliasMapTest.class, AnnotationsTest.class, BooleanModelTest.class, ClobTest.class,
+ ConcurrencyTest.class, EnumsTest.class, ModelsTest.class, PrimitivesTest.class,
+ RuntimeQueryTest.class, SamplesTest.class, UpdateTest.class, UpgradesTest.class, JoinTest.class,
+ UUIDTest.class, ViewsTest.class, ForeignKeyTest.class, TransactionTest.class })
+public class IciqlSuite {
+
+ private static final TestDb[] TEST_DBS = {
+ new TestDb("H2", true, true, "jdbc:h2:mem:iciql"),
+ new TestDb("H2", true, false, "jdbc:h2:file:testdbs/h2/iciql"),
+ new TestDb("H2", false, false, "jdbc:h2:tcp://localhost/"
+ + new File(System.getProperty("user.dir")).getAbsolutePath() + "/testdbs/h2tcp/iciql"),
+ new TestDb("HSQL", true, true, "jdbc:hsqldb:mem:iciql"),
+ new TestDb("HSQL", true, false, "jdbc:hsqldb:file:testdbs/hsql/iciql"),
+ new TestDb("HSQL", false, false, "jdbc:hsqldb:hsql://localhost/iciql"),
+ new TestDb("Derby", true, true, "jdbc:derby:memory:iciql;create=true"),
+ new TestDb("Derby", true, false, "jdbc:derby:directory:testdbs/derby/iciql;create=true"),
+ new TestDb("MySQL", false, false, "jdbc:mysql://localhost:7000/iciql", "sa", "sa"),
+ new TestDb("PostgreSQL", false, false, "jdbc:postgresql://localhost:5432/iciql", "sa", "sa") };
+
+ private static final TestDb DEFAULT_TEST_DB = TEST_DBS[0];
+
+ private static final PrintStream ERR = System.err;
+
+ private static PrintStream out = System.out;
+
+ private static Map<String, PoolableConnectionFactory> connectionFactories = Utils
+ .newSynchronizedHashMap();
+
+ private static Map<String, PoolingDataSource> dataSources = Utils.newSynchronizedHashMap();
+
+ public static void assertStartsWith(String value, String startsWith) {
+ Assert.assertTrue(MessageFormat.format("Expected \"{0}\", got: \"{1}\"", startsWith, value),
+ value.startsWith(startsWith));
+ }
+
+ public static void assertEqualsIgnoreCase(String expected, String actual) {
+ Assert.assertTrue(MessageFormat.format("Expected \"{0}\", got: \"{1}\"", expected, actual),
+ expected.equalsIgnoreCase(actual));
+ }
+
+ public static boolean equivalentTo(double expected, double actual) {
+ if (Double.compare(expected, actual) == 0) {
+ return true;
+ }
+ return Math.abs(expected - actual) <= 0.000001d;
+ }
+
+ /**
+ * Open a new Db object. All connections are cached and re-used to eliminate
+ * embedded database startup costs.
+ *
+ * @return a fresh Db object
+ */
+ public static Db openNewDb() {
+ String testUrl = System.getProperty("iciql.url", DEFAULT_TEST_DB.url);
+ String testUser = System.getProperty("iciql.user", DEFAULT_TEST_DB.username);
+ String testPassword = System.getProperty("iciql.password", DEFAULT_TEST_DB.password);
+
+ Db db = null;
+ PoolingDataSource dataSource = dataSources.get(testUrl);
+ if (dataSource == null) {
+ ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(testUrl, testUser,
+ testPassword);
+ GenericObjectPool pool = new GenericObjectPool();
+ pool.setWhenExhaustedAction(GenericObjectPool.WHEN_EXHAUSTED_GROW);
+ PoolableConnectionFactory factory = new PoolableConnectionFactory(connectionFactory, pool, null,
+ null, false, true);
+ dataSource = new PoolingDataSource(pool);
+ dataSources.put(testUrl, dataSource);
+ connectionFactories.put(testUrl, factory);
+ }
+ db = Db.open(dataSource);
+
+ // drop views
+ db.dropView(ProductView.class);
+ db.dropView(ProductViewInherited.class);
+ db.dropView(ProductViewFromQuery.class);
+ db.dropView(ProductViewInheritedComplex.class);
+
+ // drop tables
+ db.dropTable(BooleanModel.class);
+ db.dropTable(ComplexObject.class);
+ db.dropTable(Customer.class);
+ db.dropTable(DefaultValuesModel.class);
+ db.dropTable(EnumIdModel.class);
+ db.dropTable(EnumOrdinalModel.class);
+ db.dropTable(EnumStringModel.class);
+ db.dropTable(Order.class);
+ db.dropTable(PrimitivesModel.class);
+ db.dropTable(Product.class);
+ db.dropTable(ProductAnnotationOnly.class);
+ db.dropTable(ProductInheritedAnnotation.class);
+ db.dropTable(ProductMixedAnnotation.class);
+ db.dropTable(SupportedTypes.class);
+ db.dropTable(JoinTest.UserId.class);
+ db.dropTable(JoinTest.UserNote.class);
+ db.dropTable(EnumsTest.BadEnums.class);
+ db.dropTable(MultipleBoolsModel.class);
+ db.dropTable(ProductAnnotationOnlyWithForeignKey.class);
+ db.dropTable(CategoryAnnotationOnly.class);
+
+ return db;
+ }
+
+ /**
+ * Open the current database.
+ *
+ * @return the current database
+ */
+ public static Db openCurrentDb() {
+ String testUrl = System.getProperty("iciql.url", DEFAULT_TEST_DB.url);
+ String testUser = System.getProperty("iciql.user", DEFAULT_TEST_DB.username);
+ String testPassword = System.getProperty("iciql.password", DEFAULT_TEST_DB.password);
+ return Db.open(testUrl, testUser, testPassword);
+ }
+
+ /**
+ * Returns the name of the underlying database engine for the Db object.
+ *
+ * @param db
+ * @return the database engine name
+ */
+ public static String getDatabaseEngineName(Db db) {
+ String database = "";
+ try {
+ database = db.getConnection().getMetaData().getDatabaseProductName();
+ } catch (SQLException s) {
+ }
+ return database;
+ }
+
+ /**
+ * Returns true if the underlying database engine is Derby.
+ *
+ * @param db
+ * @return true if underlying database engine is Derby
+ */
+ public static boolean isDerby(Db db) {
+ return IciqlSuite.getDatabaseEngineName(db).equals("Apache Derby");
+ }
+
+ /**
+ * Returns true if the underlying database engine is H2.
+ *
+ * @param db
+ * @return true if underlying database engine is H2
+ */
+ public static boolean isH2(Db db) {
+ return IciqlSuite.getDatabaseEngineName(db).equals("H2");
+ }
+
+ /**
+ * Returns true if the underlying database engine is MySQL.
+ *
+ * @param db
+ * @return true if underlying database engine is MySQL
+ */
+ public static boolean isMySQL(Db db) {
+ return IciqlSuite.getDatabaseEngineName(db).equals("MySQL");
+ }
+
+ /**
+ * Gets the default schema of the underlying database engine.
+ *
+ * @param db
+ * @return the default schema
+ */
+ public static String getDefaultSchema(Db db) {
+ if (isDerby(db)) {
+ // Derby sets default schema name to username
+ return "SA";
+ } else if (isMySQL(db)) {
+ // MySQL does not have schemas
+ return null;
+ }
+
+ return "PUBLIC";
+ }
+
+ /**
+ * Main entry point for the test suite. Executing this method will run the
+ * test suite on all registered databases.
+ *
+ * @param args
+ * @throws Exception
+ */
+ public static void main(String... args) throws Exception {
+ Params params = new Params();
+ JCommander jc = new JCommander(params);
+ try {
+ jc.parse(args);
+ } catch (ParameterException t) {
+ usage(jc, t);
+ }
+
+ // Replace System.out with a file
+ if (!StringUtils.isNullOrEmpty(params.dbPerformanceFile)) {
+ out = new PrintStream(params.dbPerformanceFile);
+ System.setErr(out);
+ }
+
+ deleteRecursively(new File("testdbs"));
+
+ // Start the HSQL and H2 servers in-process
+ org.hsqldb.Server hsql = startHSQL();
+ org.h2.tools.Server h2 = startH2();
+
+ // Statement logging
+ final FileWriter statementWriter;
+ if (StringUtils.isNullOrEmpty(params.sqlStatementsFile)) {
+ statementWriter = null;
+ } else {
+ statementWriter = new FileWriter(params.sqlStatementsFile);
+ }
+ IciqlListener statementListener = new IciqlListener() {
+ @Override
+ public void logIciql(StatementType type, String statement) {
+ if (statementWriter == null) {
+ return;
+ }
+ try {
+ statementWriter.append(statement);
+ statementWriter.append('\n');
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ IciqlLogger.registerListener(statementListener);
+
+ SuiteClasses suiteClasses = IciqlSuite.class.getAnnotation(SuiteClasses.class);
+ long quickestDatabase = Long.MAX_VALUE;
+ String dividerMajor = buildDivider('*', 79);
+ String dividerMinor = buildDivider('-', 79);
+
+ // Header
+ out.println(dividerMajor);
+ out.println(MessageFormat.format("{0} {1} ({2}) testing {3} database configurations", Constants.NAME,
+ Constants.VERSION, Constants.VERSION_DATE, TEST_DBS.length));
+ out.println(dividerMajor);
+ out.println();
+
+ showProperty("java.vendor");
+ showProperty("java.runtime.version");
+ showProperty("java.vm.name");
+ showProperty("os.name");
+ showProperty("os.version");
+ showProperty("os.arch");
+ showProperty("available processors", "" + Runtime.getRuntime().availableProcessors());
+ showProperty(
+ "available memory",
+ MessageFormat.format("{0,number,0.0} GB", ((double) Runtime.getRuntime().maxMemory())
+ / (1024 * 1024)));
+ out.println();
+
+ // Test a database
+ long lastCount = 0;
+ for (TestDb testDb : TEST_DBS) {
+ out.println(dividerMinor);
+ out.println("Testing " + testDb.describeDatabase());
+ out.println(" " + testDb.url);
+ out.println(dividerMinor);
+
+ // inject a database section delimiter in the statement log
+ if (statementWriter != null) {
+ statementWriter.append("\n\n");
+ statementWriter.append("# ").append(dividerMinor).append('\n');
+ statementWriter.append("# ").append("Testing " + testDb.describeDatabase()).append('\n');
+ statementWriter.append("# ").append(dividerMinor).append('\n');
+ statementWriter.append("\n\n");
+ }
+
+ if (testDb.getVersion().equals("OFFLINE")) {
+ // Database not available
+ out.println("Skipping. Could not find " + testDb.url);
+ out.println();
+ } else {
+ // Setup system properties
+ System.setProperty("iciql.url", testDb.url);
+ System.setProperty("iciql.user", testDb.username);
+ System.setProperty("iciql.password", testDb.password);
+
+ // Test database
+ Result result = JUnitCore.runClasses(suiteClasses.value());
+
+ // Report results
+ testDb.runtime = result.getRunTime();
+ if (testDb.runtime < quickestDatabase) {
+ quickestDatabase = testDb.runtime;
+ }
+ testDb.statements = IciqlLogger.getTotalCount() - lastCount;
+ // reset total count for next database
+ lastCount = IciqlLogger.getTotalCount();
+
+ out.println(MessageFormat.format(
+ "{0} tests ({1} failures, {2} ignores) {3} statements in {4,number,0.000} secs",
+ result.getRunCount(), result.getFailureCount(), result.getIgnoreCount(),
+ testDb.statements, result.getRunTime() / 1000f));
+
+ if (result.getFailureCount() == 0) {
+ out.println();
+ out.println(" 100% successful test suite run.");
+ out.println();
+ } else {
+ for (Failure failure : result.getFailures()) {
+ out.println(MessageFormat.format("\n + {0}\n {1}", failure.getTestHeader(),
+ failure.getMessage()));
+ }
+ out.println();
+ }
+ }
+ }
+
+ // Display runtime results sorted by performance leader
+ out.println();
+ out.println(dividerMajor);
+ out.println(MessageFormat.format("{0} {1} ({2}) test suite performance results", Constants.NAME,
+ Constants.VERSION, Constants.VERSION_DATE));
+ out.println(dividerMajor);
+ List<TestDb> dbs = Arrays.asList(TEST_DBS);
+ Collections.sort(dbs);
+
+ out.println(MessageFormat.format("{0} {1} {2} {3} {4}", StringUtils.pad("Name", 11, " ", true),
+ StringUtils.pad("Type", 5, " ", true), StringUtils.pad("Version", 23, " ", true),
+ StringUtils.pad("Stats/Sec", 10, " ", true), "Runtime"));
+ out.println(dividerMinor);
+ for (TestDb testDb : dbs) {
+ DecimalFormat df = new DecimalFormat("0.0");
+ out.println(MessageFormat.format("{0} {1} {2} {3} {4} {5}s ({6,number,0.0}x)",
+ StringUtils.pad(testDb.name, 11, " ", true), testDb.isEmbedded ? "E" : "T",
+ testDb.isMemory ? "M" : "F", StringUtils.pad(testDb.getVersion(), 21, " ", true),
+ StringUtils.pad("" + testDb.getStatementRate(), 10, " ", false),
+ StringUtils.pad(df.format(testDb.getRuntime()), 8, " ", false), ((double) testDb.runtime)
+ / quickestDatabase));
+ }
+ out.println(dividerMinor);
+ out.println(" E = embedded connection");
+ out.println(" T = tcp/ip connection");
+ out.println(" M = memory database");
+ out.println(" F = file/persistent database");
+
+ // cleanup
+ for (PoolableConnectionFactory factory : connectionFactories.values()) {
+ factory.getPool().close();
+ }
+ IciqlLogger.unregisterListener(statementListener);
+ out.close();
+ System.setErr(ERR);
+ if (statementWriter != null) {
+ statementWriter.close();
+ }
+ hsql.stop();
+ h2.stop();
+ System.exit(0);
+ }
+
+ private static void showProperty(String name) {
+ showProperty(name, System.getProperty(name));
+ }
+
+ private static void showProperty(String name, String value) {
+ out.print(' ');
+ out.print(StringUtils.pad(name, 25, " ", true));
+ out.println(value);
+ }
+
+ private static void usage(JCommander jc, ParameterException t) {
+ System.out.println(Constants.NAME + " test suite v" + Constants.VERSION);
+ System.out.println();
+ if (t != null) {
+ System.out.println(t.getMessage());
+ System.out.println();
+ }
+ if (jc != null) {
+ jc.usage();
+ }
+ System.exit(0);
+ }
+
+ private static String buildDivider(char c, int length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < length; i++) {
+ sb.append(c);
+ }
+ return sb.toString();
+ }
+
+ private static void deleteRecursively(File f) {
+ if (f.isDirectory()) {
+ for (File file : f.listFiles()) {
+ if (file.isDirectory()) {
+ deleteRecursively(file);
+ }
+ file.delete();
+ }
+ }
+ f.delete();
+ }
+
+ /**
+ * Start an HSQL tcp server.
+ *
+ * @return an HSQL server instance
+ * @throws Exception
+ */
+ private static org.hsqldb.Server startHSQL() throws Exception {
+ HsqlProperties p = new HsqlProperties();
+ String db = new File(System.getProperty("user.dir")).getAbsolutePath() + "/testdbs/hsqltcp/iciql";
+ p.setProperty("server.database.0", "file:" + db);
+ p.setProperty("server.dbname.0", "iciql");
+ // set up the rest of properties
+
+ // alternative to the above is
+ org.hsqldb.Server server = new org.hsqldb.Server();
+ server.setProperties(p);
+ server.setLogWriter(null);
+ server.setErrWriter(null);
+ server.start();
+ return server;
+ }
+
+ /**
+ * Start the H2 tcp server.
+ *
+ * @return an H2 server instance
+ * @throws Exception
+ */
+ private static org.h2.tools.Server startH2() throws Exception {
+ org.h2.tools.Server server = org.h2.tools.Server.createTcpServer();
+ server.start();
+ return server;
+ }
+
+ /**
+ * Represents a test database url.
+ */
+ private static class TestDb implements Comparable<TestDb> {
+ final String name;
+ boolean isEmbedded;
+ boolean isMemory;
+ final String url;
+ final String username;
+ final String password;
+ String version;
+ long runtime;
+ long statements;
+
+ TestDb(String name, boolean isEmbedded, boolean isMemory, String url) {
+ this(name, isEmbedded, isMemory, url, "sa", "");
+ }
+
+ TestDb(String name, boolean isEmbedded, boolean isMemory, String url, String username, String password) {
+ this.name = name;
+ this.isEmbedded = isEmbedded;
+ this.isMemory = isMemory;
+ this.url = url;
+ this.username = username;
+ this.password = password;
+ }
+
+ double getRuntime() {
+ return runtime / 1000d;
+ }
+
+ int getStatementRate() {
+ return Double.valueOf(((double) statements) / (runtime / 1000d)).intValue();
+ }
+
+ String describeDatabase() {
+ StringBuilder sb = new StringBuilder(name);
+ sb.append(" ");
+ sb.append(getVersion());
+ return sb.toString();
+ }
+
+ String getVersion() {
+ if (version == null) {
+ try {
+ Db db = Db.open(url, username, password);
+ version = db.getConnection().getMetaData().getDatabaseProductVersion();
+ db.close();
+ return version;
+ } catch (Throwable t) {
+ version = "OFFLINE";
+ }
+ }
+ return version;
+ }
+
+ @Override
+ public int compareTo(TestDb o) {
+ if (runtime == 0) {
+ return 1;
+ }
+ if (o.runtime == 0) {
+ return -1;
+ }
+ int r1 = getStatementRate();
+ int r2 = o.getStatementRate();
+ if (r1 == r2) {
+ return 0;
+ }
+ if (r1 < r2) {
+ return 1;
+ }
+ return -1;
+ }
+ }
+
+ /**
+ * Command-line parameters for TestSuite.
+ */
+ @Parameters(separators = " ")
+ private static class Params {
+
+ @Parameter(names = { "--dbFile" }, description = "Database performance results text file", required = false)
+ public String dbPerformanceFile;
+
+ @Parameter(names = { "--sqlFile" }, description = "SQL statements log file", required = false)
+ public String sqlStatementsFile;
+ }
+}
\ No newline at end of file diff --git a/src/test/java/com/iciql/test/JoinTest.java b/src/test/java/com/iciql/test/JoinTest.java new file mode 100644 index 0000000..0e5e39d --- /dev/null +++ b/src/test/java/com/iciql/test/JoinTest.java @@ -0,0 +1,173 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; + +import java.util.Arrays; +import java.util.List; + +import org.junit.After; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQTable; +import com.iciql.QueryWhere; + +/** + * Tests of Joins. + */ +public class JoinTest { + + Db db; + + @Before + public void setup() { + db = IciqlSuite.openNewDb(); + + db.insertAll(UserId.getList()); + db.insertAll(UserNote.getList()); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testPrimitiveJoin() throws Exception { + final UserId u = new UserId(); + final UserNote n = new UserNote(); + + List<UserNote> notes = db.from(u).innerJoin(n).on(u.id).is(n.userId).where(u.id).is(2) + .select(new UserNote() { + { + userId = n.userId; + noteId = n.noteId; + text = n.text; + } + }); + assertEquals(3, notes.size()); + } + + @Test + public void testJoin() throws Exception { + final UserId u = new UserId(); + final UserNote n = new UserNote(); + + // this query returns 1 UserId if the user has a note + // it's purpose is to confirm fluency/type-safety on a very simple + // join case where the main table is filtered/reduced by hits in a + // related table + + List<UserId> users = db.from(u).innerJoin(n).on(u.id).is(n.userId).where(u.id).is(2).selectDistinct(); + + assertEquals(1, users.size()); + assertEquals(2, users.get(0).id); + } + + @Test + public void testLeftJoin() throws Exception { + final UserId u = new UserId(); + final UserNote n = new UserNote(); + + List<UserId> notes = db.from(u).leftJoin(n).on(u.id).is(n.userId).where(u.id).is(4).select(); + assertEquals(1, notes.size()); + assertEquals(4, notes.get(0).id); + } + + @Test + public void testSubQuery() throws Exception { + final UserId u = new UserId(); + final UserNote n = new UserNote(); + + QueryWhere<UserId> q = db.from(u).where(u.id).in(db.from(n).where(n.userId).exceeds(0).subQuery(n.userId)); + List<UserId> notes = q.select(); + assertEquals(3, notes.size()); + + // do not test MySQL on this statement because the databases + if (IciqlSuite.isMySQL(db)) { + assertEquals("SELECT * FROM UserId WHERE `id` in (SELECT `userId` FROM UserNote WHERE `userId` > 0 )", q.toSQL()); + } else { + assertEquals("SELECT * FROM UserId WHERE id in (SELECT userId FROM UserNote WHERE userId > 0 )", q.toSQL()); + } + } + + @IQTable + public static class UserId { + + @IQColumn(primaryKey = true) + public int id; + + @IQColumn(length = 10) + public String name; + + public UserId() { + // public constructor + } + + public UserId(int id, String name) { + this.id = id; + this.name = name; + } + + public String toString() { + return name + " (" + id + ")"; + } + + public static List<UserId> getList() { + UserId[] list = { new UserId(1, "Tom"), new UserId(2, "Dick"), new UserId(3, "Harry"), new UserId(4, "Jack") }; + return Arrays.asList(list); + } + } + + @IQTable + public static class UserNote { + + @IQColumn(autoIncrement = true, primaryKey = true) + public int noteId; + + @IQColumn + public int userId; + + @IQColumn(length = 10) + public String text; + + public UserNote() { + // public constructor + } + + public UserNote(int userId, String text) { + this.userId = userId; + this.text = text; + } + + public String toString() { + return text; + } + + public static List<UserNote> getList() { + UserNote[] list = { new UserNote(1, "A"), new UserNote(2, "B"), new UserNote(3, "C"), + new UserNote(1, "D"), new UserNote(2, "E"), new UserNote(3, "F"), new UserNote(1, "G"), + new UserNote(2, "H"), new UserNote(3, "I"), }; + return Arrays.asList(list); + } + } +} diff --git a/src/test/java/com/iciql/test/ModelsTest.java b/src/test/java/com/iciql/test/ModelsTest.java new file mode 100644 index 0000000..c5ba27a --- /dev/null +++ b/src/test/java/com/iciql/test/ModelsTest.java @@ -0,0 +1,145 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static com.iciql.test.IciqlSuite.assertEqualsIgnoreCase; + +import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ErrorCollector; + +import com.iciql.Db; +import com.iciql.DbInspector; +import com.iciql.ValidationRemark; +import com.iciql.test.models.Product; +import com.iciql.test.models.ProductAnnotationOnly; +import com.iciql.test.models.ProductMixedAnnotation; +import com.iciql.test.models.SupportedTypes; +import com.iciql.util.StringUtils; + +/** + * Test that the mapping between classes and tables is done correctly. + */ +public class ModelsTest { + + /* + * The ErrorCollector Rule allows execution of a test to continue after the + * first problem is found and report them all at once + */ + @Rule + public ErrorCollector errorCollector = new ErrorCollector(); + + private Db db; + + @Before + public void setUp() { + db = IciqlSuite.openNewDb(); + db.insertAll(Product.getList()); + db.insertAll(ProductAnnotationOnly.getList()); + db.insertAll(ProductMixedAnnotation.getList()); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testValidateModels() { + String schemaName = IciqlSuite.getDefaultSchema(db); + DbInspector inspector = new DbInspector(db); + validateModel(inspector, schemaName, new ProductAnnotationOnly(), 2); + validateModel(inspector, schemaName, new ProductMixedAnnotation(), 4); + } + + private void validateModel(DbInspector inspector, String schemaName, Object o, int expected) { + List<ValidationRemark> remarks = inspector.validateModel(o, false); + assertTrue("validation remarks are null for " + o.getClass().getName(), remarks != null); + StringBuilder sb = new StringBuilder(); + sb.append("validation remarks for " + o.getClass().getName()); + sb.append('\n'); + for (ValidationRemark remark : remarks) { + sb.append(remark.toString()); + sb.append('\n'); + if (remark.isError()) { + errorCollector.addError(new SQLException(remark.toString())); + } + } + + if (StringUtils.isNullOrEmpty(schemaName)) { + // no schema expected + assertEquals(sb.toString(), expected - 1, remarks.size()); + } else { + assertEquals(sb.toString(), expected, remarks.size()); + assertEqualsIgnoreCase(MessageFormat.format("@IQSchema(\"{0}\")", schemaName), + remarks.get(0).message); + } + } + + @Test + public void testSupportedTypes() { + List<SupportedTypes> original = SupportedTypes.createList(); + db.insertAll(original); + List<SupportedTypes> retrieved = db.from(SupportedTypes.SAMPLE).select(); + assertEquals(original.size(), retrieved.size()); + for (int i = 0; i < original.size(); i++) { + SupportedTypes o = original.get(i); + SupportedTypes r = retrieved.get(i); + assertTrue(o.equivalentTo(r)); + } + } + + @Test + public void testModelGeneration() { + List<SupportedTypes> original = SupportedTypes.createList(); + db.insertAll(original); + DbInspector inspector = new DbInspector(db); + List<String> models = inspector.generateModel(null, "SupportedTypes", "com.iciql.test.models", true, + true); + assertEquals(1, models.size()); + // a poor test, but a start + String dbName = IciqlSuite.getDatabaseEngineName(db); + if (dbName.equals("H2")) { + assertEquals(1587, models.get(0).length()); + } else if (dbName.startsWith("HSQL")) { + // HSQL uses Double instead of Float + assertEquals(1591, models.get(0).length()); + } else if (dbName.equals("Apache Derby")) { + // Derby uses java.sql.Timestamp not java.util.Date + // Derby uses username as schema name + assertEquals(1601, models.get(0).length()); + } else if (dbName.equals("PostgreSQL")) { + assertEquals(1643, models.get(0).length()); + } else if (dbName.equals("MySQL")) { + // MySQL uses timestamp default values like + // 0000-00-00 00:00:00 and CURRENT_TIMESTAMP + assertEquals(1673, models.get(0).length()); + } else { + // unknown database + assertEquals(0, models.get(0).length()); + } + } +} diff --git a/src/test/java/com/iciql/test/PrimitivesTest.java b/src/test/java/com/iciql/test/PrimitivesTest.java new file mode 100644 index 0000000..3d3811e --- /dev/null +++ b/src/test/java/com/iciql/test/PrimitivesTest.java @@ -0,0 +1,102 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.IciqlException;
+import com.iciql.test.models.MultipleBoolsModel;
+import com.iciql.test.models.PrimitivesModel;
+
+/**
+ * Tests primitives with autoboxing within the framework.
+ */
+public class PrimitivesTest {
+
+ @Test
+ public void testPrimitives() {
+ Db db = IciqlSuite.openNewDb();
+
+ // insert random models in reverse order
+ List<PrimitivesModel> models = PrimitivesModel.getList();
+ PrimitivesModel model = models.get(0);
+ Collections.reverse(models);
+ // insert them in reverse order
+ db.insertAll(models);
+
+ PrimitivesModel p = new PrimitivesModel();
+
+ // retrieve model and compare
+ PrimitivesModel retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();
+ assertTrue(model.equivalentTo(retrievedModel));
+
+ retrievedModel = db.from(p).where("mylong = ? and myinteger = ?", model.myLong, model.myInteger)
+ .selectFirst();
+ assertTrue(model.equivalentTo(retrievedModel));
+
+ // retrieve with conditions and compare
+ retrievedModel = db.from(p).where(p.myLong).is(model.myLong).and(p.myInteger).is(model.myInteger)
+ .selectFirst();
+ assertTrue(model.equivalentTo(retrievedModel));
+
+ // set myInteger & myDouble
+ db.from(p).set(p.myInteger).to(10).set(p.myDouble).to(3.0d).where(p.myLong).is(model.myLong).update();
+ retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();
+
+ assertEquals(10, retrievedModel.myInteger);
+ assertEquals(3d, retrievedModel.myDouble, 0.001d);
+
+ // increment my double by pi
+ db.from(p).increment(p.myDouble).by(3.14d).update();
+ retrievedModel = db.from(p).orderBy(p.myLong).selectFirst();
+ assertEquals(6.14d, retrievedModel.myDouble, 0.001d);
+
+ // test order by
+ List<PrimitivesModel> list = db.from(p).orderBy(p.myLong).select();
+ assertEquals(models.size(), list.size());
+ assertEquals("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]", list.toString());
+
+ // test model update
+ retrievedModel.myInteger = 1337;
+ assertEquals(1, db.update(retrievedModel));
+ assertEquals(1, db.delete(retrievedModel));
+
+ db.close();
+ }
+
+ @Test
+ public void testMultipleBooleans() {
+ Db db = IciqlSuite.openNewDb();
+ db.insertAll(MultipleBoolsModel.getList());
+
+ MultipleBoolsModel m = new MultipleBoolsModel();
+ try {
+ db.from(m).where(m.a).is(true).select();
+ assertTrue(false);
+ } catch (IciqlException e) {
+ assertTrue(true);
+ }
+ db.close();
+ }
+}
diff --git a/src/test/java/com/iciql/test/RuntimeQueryTest.java b/src/test/java/com/iciql/test/RuntimeQueryTest.java new file mode 100644 index 0000000..c23527f --- /dev/null +++ b/src/test/java/com/iciql/test/RuntimeQueryTest.java @@ -0,0 +1,199 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.junit.Assume;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.QueryWhere;
+import com.iciql.test.models.EnumModels.Tree;
+import com.iciql.test.models.Product;
+import com.iciql.test.models.StaticQueries;
+import com.iciql.util.JdbcUtils;
+import com.iciql.util.Utils;
+
+/**
+ * Tests the runtime dynamic query function.
+ */
+public class RuntimeQueryTest {
+
+ @Test
+ public void testParameters() {
+ Db db = IciqlSuite.openNewDb();
+
+ // do not test non-H2 databases because dialects will get in the way
+ // e.g. column quoting, etc
+ Assume.assumeTrue(IciqlSuite.isH2(db));
+
+ Product p = new Product();
+ String q1 = db.from(p).where(p.unitsInStock).isParameter().and(p.productName).likeParameter().orderBy(p.productId).toSQL();
+ String q2 = db.from(p).where(p.unitsInStock).lessThan(100).and(p.productName).like("test").or(p.productName).likeParameter().orderBy(p.productId).toSQL();
+
+ StaticQueries.StaticModel1 m1 = new StaticQueries.StaticModel1();
+ String q3 = db.from(m1).where(m1.myTree).is(Tree.MAPLE).and(m1.myTree).isParameter().toSQL();
+
+ StaticQueries.StaticModel2 m2 = new StaticQueries.StaticModel2();
+ String q4 = db.from(m2).where(m2.myTree).is(Tree.MAPLE).and(m2.myTree).isParameter().toSQL();
+
+ StaticQueries.StaticModel3 m3 = new StaticQueries.StaticModel3();
+ String q5 = db.from(m3).where(m3.myTree).is(Tree.MAPLE).and(m3.myTree).isParameter().toSQL();
+
+ long now = System.currentTimeMillis();
+ java.sql.Date aDate = new java.sql.Date(now);
+ java.sql.Time aTime = new java.sql.Time(now);
+ java.sql.Timestamp aTimestamp = new java.sql.Timestamp(now);
+
+ String q6 = db.from(m1).where(m1.myDate).is(aDate).and(m1.myDate).isParameter().toSQL();
+ String q7 = db.from(m1).where(m1.myTime).is(aTime).and(m1.myTime).isParameter().toSQL();
+ String q8 = db.from(m1).where(m1.myTimestamp).is(aTimestamp).and(m1.myTimestamp).isParameter().toSQL();
+
+ db.close();
+ assertEquals("SELECT * FROM Product WHERE unitsInStock = ? AND productName LIKE ? ORDER BY productId", q1);
+ assertEquals("SELECT * FROM Product WHERE unitsInStock < 100 AND productName LIKE 'test' OR productName LIKE ? ORDER BY productId", q2);
+
+ assertEquals("SELECT * FROM StaticQueryTest1 WHERE myTree = 'MAPLE' AND myTree = ?", q3);
+ assertEquals("SELECT * FROM StaticQueryTest2 WHERE myTree = 50 AND myTree = ?", q4);
+ assertEquals("SELECT * FROM StaticQueryTest3 WHERE myTree = 4 AND myTree = ?", q5);
+
+ java.util.Date refDate = new java.util.Date(now);
+ assertEquals("SELECT * FROM StaticQueryTest1 WHERE myDate = '" + new SimpleDateFormat("yyyy-MM-dd").format(refDate) + "' AND myDate = ?", q6);
+ assertEquals("SELECT * FROM StaticQueryTest1 WHERE myTime = '" + new SimpleDateFormat("HH:mm:ss").format(refDate) + "' AND myTime = ?", q7);
+ assertEquals("SELECT * FROM StaticQueryTest1 WHERE myTimestamp = '" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(refDate) + "' AND myTimestamp = ?", q8);
+ }
+
+ @Test
+ public void testRuntimeSet() {
+ Db db = IciqlSuite.openNewDb();
+
+ // do not test non-H2 databases because dialects will get in the way
+ // e.g. column quoting, etc
+ Assume.assumeTrue(IciqlSuite.isH2(db));
+
+ StaticQueries.StaticModel1 m = new StaticQueries.StaticModel1();
+ String q = db.from(m).set(m.myTimestamp).toParameter().where(m.id).isParameter().toSQL();
+ db.close();
+
+ assertEquals("UPDATE StaticQueryTest1 SET myTimestamp = ? WHERE id = ?", q);
+ }
+
+ @Test
+ public void testRuntimeSelectWildcards() {
+ Db db = IciqlSuite.openNewDb();
+
+ // do not test non-H2 databases because dialects will get in the way
+ // e.g. column quoting, etc
+ Assume.assumeTrue(IciqlSuite.isH2(db));
+
+ StaticQueries.StaticModel1 m1 = new StaticQueries.StaticModel1();
+ StaticQueries.StaticModel2 m2 = new StaticQueries.StaticModel2();
+ StaticQueries.StaticModel2 m3 = new StaticQueries.StaticModel2();
+
+ int t0 = Utils.AS_COUNTER.get() + 1;
+ int t1 = t0 + 1;
+
+ QueryWhere<?> where = db.from(m1).innerJoin(m2).on(m1.id).is(m2.id).where(m2.myTree).is(Tree.MAPLE);
+ String q1 = where.toSQL(false);
+ String q2 = where.toSQL(true);
+ String q3 = where.toSQL(false, m1);
+ String q4 = where.toSQL(true, m1);
+ String q5 = where.toSQL(false, m2);
+ String q6 = where.toSQL(true, m2);
+
+ // test unused alias
+ String q7 = where.toSQL(true, m3);
+
+ db.close();
+
+ assertEquals(MessageFormat.format("SELECT * FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q1);
+ assertEquals(MessageFormat.format("SELECT DISTINCT * FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q2);
+
+ assertEquals(MessageFormat.format("SELECT T{0,number,0}.* FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q3);
+ assertEquals(MessageFormat.format("SELECT DISTINCT T{0,number,0}.* FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q4);
+
+ assertEquals(MessageFormat.format("SELECT T{1,number,0}.* FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q5);
+ assertEquals(MessageFormat.format("SELECT DISTINCT T{1,number,0}.* FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q6);
+
+ assertEquals(MessageFormat.format("SELECT DISTINCT * FROM StaticQueryTest1 AS T{0,number,0} INNER JOIN StaticQueryTest2 AS T{1,number,0} ON T{0,number,0}.id = T{1,number,0}.id WHERE T{1,number,0}.myTree = 50", t0, t1), q7);
+ }
+
+ @Test
+ public void testRuntimeQuery() {
+ Db db = IciqlSuite.openNewDb();
+ db.insertAll(Product.getList());
+
+ Product p = new Product();
+ List<Product> products = db.from(p).where("unitsInStock=?", 120).orderBy(p.productId).select();
+ assertEquals(1, products.size());
+
+ products = db.from(p).where("unitsInStock=? and productName like ? order by productId", 0, "Chef%")
+ .select();
+ assertEquals(1, products.size());
+
+ db.close();
+ }
+
+ @Test
+ public void testExecuteQuery() throws SQLException {
+ Db db = IciqlSuite.openNewDb();
+ db.insertAll(Product.getList());
+
+ // test plain statement
+ List<Product> products = db.executeQuery(Product.class,
+ "select * from product where unitsInStock=120");
+ assertEquals(1, products.size());
+ assertEquals("Condiments", products.get(0).category);
+
+ // test prepared statement
+ products = db.executeQuery(Product.class, "select * from product where unitsInStock=?", 120);
+ assertEquals(1, products.size());
+ assertEquals("Condiments", products.get(0).category);
+
+ db.close();
+ }
+
+ @Test
+ public void testBuildObjects() throws SQLException {
+ Db db = IciqlSuite.openNewDb();
+ db.insertAll(Product.getList());
+
+ // test plain statement
+ ResultSet rs = db.executeQuery("select * from product where unitsInStock=120");
+ List<Product> products = db.buildObjects(Product.class, rs);
+ JdbcUtils.closeSilently(rs, true);
+
+ assertEquals(1, products.size());
+ assertEquals("Condiments", products.get(0).category);
+
+ // test prepared statement
+ rs = db.executeQuery("select * from product where unitsInStock=?", 120);
+ products = db.buildObjects(Product.class, rs);
+ JdbcUtils.closeSilently(rs, true);
+
+ assertEquals(1, products.size());
+ assertEquals("Condiments", products.get(0).category);
+
+ db.close();
+ }
+}
diff --git a/src/test/java/com/iciql/test/SamplesTest.java b/src/test/java/com/iciql/test/SamplesTest.java new file mode 100644 index 0000000..49a64f5 --- /dev/null +++ b/src/test/java/com/iciql/test/SamplesTest.java @@ -0,0 +1,442 @@ +/*
+ * 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.test;
+
+import static com.iciql.Function.count;
+import static com.iciql.Function.isNull;
+import static com.iciql.Function.length;
+import static com.iciql.Function.max;
+import static com.iciql.Function.min;
+import static com.iciql.Function.not;
+import static com.iciql.Function.sum;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.Filter;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.test.models.ComplexObject;
+import com.iciql.test.models.Customer;
+import com.iciql.test.models.Order;
+import com.iciql.test.models.Product;
+import com.iciql.test.models.SupportedTypes;
+
+/**
+ * This is the implementation of the 101 LINQ Samples as described in
+ * http://msdn2.microsoft.com/en-us/vcsharp/aa336760.aspx
+ */
+public class SamplesTest {
+
+ /**
+ * This object represents a database (actually a connection to the
+ * database).
+ */
+
+ Db db;
+
+ @Before
+ public void setUp() {
+ db = IciqlSuite.openNewDb();
+ db.insertAll(Product.getList());
+ db.insertAll(Customer.getList());
+ db.insertAll(Order.getList());
+ db.insertAll(ComplexObject.getList());
+ }
+
+ @After
+ public void tearDown() {
+ db.close();
+ }
+
+ /**
+ * A simple test table. The columns are in a different order than in the
+ * database.
+ */
+ public static class TestReverse {
+ public String name;
+ public Integer id;
+ }
+
+ @Test
+ public void testReverseColumns() {
+ db.executeUpdate("create table TestReverse(id int, name varchar(10), additional varchar(10))");
+ TestReverse t = new TestReverse();
+ t.id = 10;
+ t.name = "Hello";
+ db.insert(t);
+ TestReverse check = db.from(new TestReverse()).selectFirst();
+ assertEquals(t.name, check.name);
+ assertEquals(t.id, check.id);
+ db.executeUpdate("DROP TABLE testreverse");
+ }
+
+ @Test
+ public void testWhereSimple2() {
+
+ // var soldOutProducts =
+ // from p in products
+ // where p.UnitsInStock == 0
+ // select p;
+
+ Product p = new Product();
+ List<Product> soldOutProducts = db.from(p).where(p.unitsInStock).is(0).orderBy(p.productId).select();
+ List<Product> soldOutProducts2 = db.from(p).where(p.unitsInStock).is(0).orderBy(p.productId).select(p);
+
+ assertEquals("[Chef Anton's Gumbo Mix: 0]", soldOutProducts.toString());
+ assertEquals(soldOutProducts.toString(), soldOutProducts2.toString());
+ }
+
+ @Test
+ public void testWhereSimple3() {
+
+ // var expensiveInStockProducts =
+ // from p in products
+ // where p.UnitsInStock > 0
+ // && p.UnitPrice > 3.00M
+ // select p;
+
+ Product p = new Product();
+ List<Product> expensiveInStockProducts = db.from(p).where(p.unitsInStock).exceeds(0).and(p.unitPrice)
+ .exceeds(30.0).orderBy(p.productId).select();
+
+ assertEquals("[Northwoods Cranberry Sauce: 6, Mishi Kobe Niku: 29, Ikura: 31]",
+ expensiveInStockProducts.toString());
+ }
+
+ @Test
+ public void testWhereSimple4() {
+
+ // var waCustomers =
+ // from c in customers
+ // where c.Region == "WA"
+ // select c;
+
+ Customer c = new Customer();
+ List<Customer> waCustomers = db.from(c).where(c.region).is("WA").select();
+
+ assertEquals("[ALFKI, ANATR]", waCustomers.toString());
+ }
+
+ @Test
+ public void testSelectSimple2() {
+
+ // var productNames =
+ // from p in products
+ // select p.ProductName;
+
+ Product p = new Product();
+ List<String> productNames = db.from(p).orderBy(p.productId).select(p.productName);
+
+ List<Product> products = Product.getList();
+ for (int i = 0; i < products.size(); i++) {
+ assertEquals(products.get(i).productName, productNames.get(i));
+ }
+ }
+
+ /**
+ * A result set class containing the product name and price.
+ */
+ public static class ProductPrice {
+ public String productName;
+ public String category;
+ @IQColumn(name = "unitPrice")
+ public Double price;
+ }
+
+ @Test
+ public void testAnonymousTypes3() {
+
+ // var productInfos =
+ // from p in products
+ // select new {
+ // p.ProductName,
+ // p.Category,
+ // Price = p.UnitPrice
+ // };
+
+ final Product p = new Product();
+ List<ProductPrice> productInfos = db.from(p).orderBy(p.productId).select(new ProductPrice() {
+ {
+ productName = p.productName;
+ category = p.category;
+ price = p.unitPrice;
+ }
+ });
+
+ List<Product> products = Product.getList();
+ assertEquals(products.size(), productInfos.size());
+ for (int i = 0; i < products.size(); i++) {
+ ProductPrice pr = productInfos.get(i);
+ Product p2 = products.get(i);
+ assertEquals(p2.productName, pr.productName);
+ assertEquals(p2.category, pr.category);
+ assertEquals(p2.unitPrice, pr.price);
+ }
+ }
+
+ /**
+ * A result set class containing customer data and the order total.
+ */
+ public static class CustOrder {
+ public String customerId;
+ public Integer orderId;
+ public BigDecimal total;
+
+ public String toString() {
+ return customerId + ":" + orderId + ":" + total;
+ }
+ }
+
+ @Test
+ public void testSelectManyCompoundFrom2() {
+
+ // var orders =
+ // from c in customers,
+ // o in c.Orders
+ // where o.Total < 500.00M
+ // select new {
+ // c.CustomerID,
+ // o.OrderID,
+ // o.Total
+ // };
+
+ final Customer c = new Customer();
+ final Order o = new Order();
+ List<CustOrder> orders = db.from(c).innerJoin(o).on(c.customerId).is(o.customerId).where(o.total)
+ .lessThan(new BigDecimal("100.00")).orderBy(c.customerId).select(new CustOrder() {
+ {
+ customerId = c.customerId;
+ orderId = o.orderId;
+ total = o.total;
+ }
+ });
+
+ assertEquals("[ANATR:10308:88.80]", orders.toString());
+ }
+
+ @Test
+ public void testIsNull() {
+ Product p = new Product();
+ String sql = db.from(p).whereTrue(isNull(p.productName)).getSQL();
+ assertEquals("SELECT * FROM Product WHERE (" + db.getDialect().prepareColumnName("productName")
+ + " IS NULL)", sql);
+ }
+
+ @Test
+ public void testDelete() {
+ Product p = new Product();
+ int deleted = db.from(p).where(p.productName).like("A%").delete();
+ assertEquals(1, deleted);
+ deleted = db.from(p).delete();
+ assertEquals(9, deleted);
+ db.insertAll(Product.getList());
+ db.deleteAll(Product.getList());
+ assertEquals(0, db.from(p).selectCount());
+ db.insertAll(Product.getList());
+ }
+
+ @Test
+ public void testOrAndNot() {
+ Product p = new Product();
+ String sql = db.from(p).whereTrue(not(isNull(p.productName))).getSQL();
+ String productName = db.getDialect().prepareColumnName("productName");
+ assertEquals("SELECT * FROM Product WHERE (NOT " + productName + " IS NULL)", sql);
+ sql = db.from(p).whereTrue(not(isNull(p.productName))).getSQL();
+ assertEquals("SELECT * FROM Product WHERE (NOT " + productName + " IS NULL)", sql);
+ sql = db.from(p).whereTrue(db.test(p.productId).is(1)).getSQL();
+ String productId = db.getDialect().prepareColumnName("productId");
+ assertEquals("SELECT * FROM Product WHERE ((" + productId + " = ?))", sql);
+ }
+
+ @Test
+ public void testLength() {
+ Product p = new Product();
+ List<Integer> lengths = db.from(p).where(length(p.productName)).lessThan(10)
+ .selectDistinct(length(p.productName));
+ // Formerly used orderBy(1) here, but that is not portable across DBs
+ Collections.sort(lengths);
+ assertEquals("[4, 5]", lengths.toString());
+ }
+
+ @Test
+ public void testSum() {
+ Product p = new Product();
+ Number sum = db.from(p).selectFirst(sum(p.unitsInStock));
+ assertEquals(323, sum.intValue());
+ Double sumPrice = db.from(p).selectFirst(sum(p.unitPrice));
+ assertEquals(313.35, sumPrice.doubleValue(), 0.001);
+ }
+
+ @Test
+ public void testMinMax() {
+ Product p = new Product();
+ Integer min = db.from(p).selectFirst(min(p.unitsInStock));
+ assertEquals(0, min.intValue());
+ String minName = db.from(p).selectFirst(min(p.productName));
+ assertEquals("Aniseed Syrup", minName);
+ Double max = db.from(p).selectFirst(max(p.unitPrice));
+ assertEquals(97.0, max.doubleValue(), 0.001);
+ }
+
+ @Test
+ public void testLike() {
+ Product p = new Product();
+ List<Product> aList = db.from(p).where(p.productName).like("Cha%").orderBy(p.productName).select();
+ assertEquals("[Chai: 39, Chang: 17]", aList.toString());
+ }
+
+ @Test
+ public void testCount() {
+ long count = db.from(new Product()).selectCount();
+ assertEquals(10, count);
+ }
+
+ @Test
+ public void testComplexObject() {
+ ComplexObject co = new ComplexObject();
+ String sql = db.from(co).where(co.id).is(1).and(co.amount).is(1L).and(co.birthday)
+ .lessThan(new java.util.Date()).and(co.created)
+ .lessThan(java.sql.Timestamp.valueOf("2005-05-05 05:05:05")).and(co.name).is("hello")
+ .and(co.time).lessThan(java.sql.Time.valueOf("23:23:23")).and(co.value)
+ .is(new BigDecimal("1")).getSQL();
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT * FROM ComplexObject WHERE ");
+ sb.append(db.getDialect().prepareColumnName("id"));
+ sb.append(" = ? AND ");
+ sb.append(db.getDialect().prepareColumnName("amount"));
+ sb.append(" = ? AND ");
+ sb.append(db.getDialect().prepareColumnName("birthday"));
+ sb.append(" < ? AND ");
+ sb.append(db.getDialect().prepareColumnName("created"));
+ sb.append(" < ? AND ");
+ sb.append(db.getDialect().prepareColumnName("name"));
+ sb.append(" = ? AND ");
+ sb.append(db.getDialect().prepareColumnName("time"));
+ sb.append(" < ? AND ");
+ sb.append(db.getDialect().prepareColumnName("value"));
+ sb.append(" = ?");
+ assertEquals(sb.toString(), sql);
+
+ long count = db.from(co).where(co.id).is(1).and(co.amount).is(1L).and(co.birthday)
+ .lessThan(new java.util.Date()).and(co.created)
+ .lessThan(java.sql.Timestamp.valueOf("2005-05-05 05:05:05")).and(co.name).is("hello")
+ .and(co.time).lessThan(java.sql.Time.valueOf("23:23:23")).and(co.value)
+ .is(new BigDecimal("1")).selectCount();
+ assertEquals(1, count);
+ }
+
+ @Test
+ public void testComplexObject2() {
+ testComplexObject2(1, "hello");
+ }
+
+ private void testComplexObject2(final int x, final String name) {
+ final ComplexObject co = new ComplexObject();
+
+ String sql = db.from(co).where(new Filter() {
+ public boolean where() {
+ return co.id == x && co.name.equals(name) && co.name.equals("hello");
+ }
+ }).getSQL();
+ StringBuilder sb = new StringBuilder();
+ sb.append("SELECT * FROM ComplexObject WHERE ");
+ sb.append(db.getDialect().prepareColumnName("id"));
+ sb.append("=? AND ?=");
+ sb.append(db.getDialect().prepareColumnName("name"));
+ sb.append(" AND 'hello'=");
+ sb.append(db.getDialect().prepareColumnName("name"));
+ assertEquals(sb.toString(), sql);
+
+ long count = db.from(co).where(new Filter() {
+ public boolean where() {
+ return co.id == x && co.name.equals(name) && co.name.equals("hello");
+ }
+ }).selectCount();
+
+ assertEquals(1, count);
+ }
+
+ @Test
+ public void testLimitOffset() {
+ Set<Integer> ids = new HashSet<Integer>();
+ Product p = new Product();
+ for (int i = 0; i < 5; i++) {
+ List<Product> products = db.from(p).limit(2).offset(2 * i).select();
+ assertTrue(products.size() == 2);
+ for (Product prod : products) {
+ assertTrue("Failed to add product id. Duplicate?", ids.add(prod.productId));
+ }
+ }
+ }
+
+ @Test
+ public void testKeyRetrieval() {
+ List<SupportedTypes> list = SupportedTypes.createList();
+ List<Long> keys = db.insertAllAndGetKeys(list);
+ Set<Long> uniqueKeys = new HashSet<Long>();
+ for (Long l : keys) {
+ assertTrue("Failed to add key. Duplicate?", uniqueKeys.add(l));
+ }
+ }
+
+ /**
+ * A result set class containing product groups.
+ */
+ public static class ProductGroup {
+ public String category;
+ public Long productCount;
+
+ public String toString() {
+ return category + ":" + productCount;
+ }
+ }
+
+ @Test
+ public void testGroup() {
+
+ // var orderGroups =
+ // from p in products
+ // group p by p.Category into g
+ // select new {
+ // Category = g.Key,
+ // Products = g
+ // };
+
+ final Product p = new Product();
+ List<ProductGroup> list = db.from(p).groupBy(p.category).orderBy(p.category)
+ .select(new ProductGroup() {
+ {
+ category = p.category;
+ productCount = count();
+ }
+ });
+ assertEquals("[Beverages:2, Condiments:5, Meat/Poultry:1, Produce:1, Seafood:1]", list.toString());
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/TransactionTest.java b/src/test/java/com/iciql/test/TransactionTest.java new file mode 100644 index 0000000..026366e --- /dev/null +++ b/src/test/java/com/iciql/test/TransactionTest.java @@ -0,0 +1,119 @@ +/*
+ * Copyright 2012 Frédéric Gaillard.
+ *
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.SQLException;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.IciqlException;
+import com.iciql.test.models.CategoryAnnotationOnly;
+import com.iciql.test.models.ProductAnnotationOnlyWithForeignKey;
+
+/**
+ * Tests of transactions.
+ */
+public class TransactionTest {
+
+ /**
+ * This object represents a database (actually a connection to the
+ * database).
+ */
+
+ private Db db;
+
+ @Before
+ public void setUp() {
+ db = IciqlSuite.openNewDb();
+
+ // tables creation
+ db.from(new CategoryAnnotationOnly());
+ db.from(new ProductAnnotationOnlyWithForeignKey());
+
+ startTransactionMode();
+ }
+
+ @After
+ public void tearDown() {
+
+ endTransactionMode();
+
+ db.dropTable(ProductAnnotationOnlyWithForeignKey.class);
+ db.dropTable(CategoryAnnotationOnly.class);
+ db.close();
+ }
+
+ @Test
+ public void testTransaction() {
+
+ // insert in 2 tables inside a transaction
+
+ // insertAll don't use save point in this transaction
+ db.insertAll(CategoryAnnotationOnly.getList());
+ db.insertAll(ProductAnnotationOnlyWithForeignKey.getList());
+
+ // don't commit changes
+ try {
+ db.getConnection().rollback();
+ } catch (SQLException e) {
+ throw new IciqlException(e, "Can't rollback");
+ }
+
+ ProductAnnotationOnlyWithForeignKey p = new ProductAnnotationOnlyWithForeignKey();
+ long count1 = db.from(p).selectCount();
+
+ CategoryAnnotationOnly c = new CategoryAnnotationOnly();
+ long count2 = db.from(c).selectCount();
+
+ // verify changes aren't committed
+ assertEquals(count1, 0L);
+ assertEquals(count2, 0L);
+ }
+
+ /**
+ * Helper to set transaction mode
+ */
+ private void startTransactionMode() {
+ db.setSkipCreate(true);
+ db.setAutoSavePoint(false);
+
+ try {
+ db.getConnection().setAutoCommit(false);
+ } catch (SQLException e) {
+ throw new IciqlException(e, "Could not change auto-commit mode");
+ }
+ }
+
+ /**
+ * Helper to return to initial mode
+ */
+ private void endTransactionMode() {
+ try {
+ db.getConnection().setAutoCommit(true);
+ } catch (SQLException e) {
+ throw new IciqlException(e, "Could not change auto-commit mode");
+ }
+ // returns to initial states
+ db.setSkipCreate(false);
+ db.setAutoSavePoint(true);
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/UUIDTest.java b/src/test/java/com/iciql/test/UUIDTest.java new file mode 100644 index 0000000..bb09c9f --- /dev/null +++ b/src/test/java/com/iciql/test/UUIDTest.java @@ -0,0 +1,115 @@ +/* + * 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.junit.After; +import org.junit.Assume; +import org.junit.Before; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQTable; + +/** + * Tests of UUID type. + * <p> + * H2 only. + */ +public class UUIDTest { + + Db db; + + @Before + public void setup() { + db = IciqlSuite.openNewDb(); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testUUIDs() throws Exception { + // do not test non-H2 databases + Assume.assumeTrue(IciqlSuite.isH2(db)); + + List<UUIDRecord> originals = UUIDRecord.getList(); + db.insertAll(originals); + UUIDRecord u = new UUIDRecord(); + List<UUIDRecord> retrieved = db.from(u).orderBy(u.id).select(); + assertEquals(originals.size(), retrieved.size()); + for (int i = 0; i < originals.size(); i++) { + UUIDRecord a = originals.get(i); + UUIDRecord b = retrieved.get(i); + assertTrue(a.equivalentTo(b)); + } + + UUIDRecord second = db.from(u).where(u.uuid).is(originals.get(1).uuid).selectFirst(); + assertTrue(originals.get(1).equivalentTo(second)); + db.dropTable(UUIDRecord.class); + } + + /** + * A simple class used in this test. + */ + @IQTable(name = "UUID_TEST") + public static class UUIDRecord { + + @IQColumn(primaryKey = true) + public Integer id; + + @IQColumn() + public UUID uuid; + + public UUIDRecord() { + // public constructor + } + + private UUIDRecord(int id) { + this.id = id; + this.uuid = UUID.randomUUID(); + } + + public boolean equivalentTo(UUIDRecord b) { + boolean same = true; + same &= id == b.id; + same &= uuid.equals(b.uuid); + return same; + } + + public String toString() { + return id + ": " + uuid; + } + + public static List<UUIDRecord> getList() { + List<UUIDRecord> list = new ArrayList<UUIDRecord>(); + for (int i = 0; i < 10; i++) { + list.add(new UUIDRecord(i + 1)); + } + return list; + } + } +} diff --git a/src/test/java/com/iciql/test/UpdateTest.java b/src/test/java/com/iciql/test/UpdateTest.java new file mode 100644 index 0000000..717c23a --- /dev/null +++ b/src/test/java/com/iciql/test/UpdateTest.java @@ -0,0 +1,160 @@ +/* + * 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.test; + +import static java.sql.Date.valueOf; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.test.models.Customer; +import com.iciql.test.models.Order; +import com.iciql.test.models.Product; + +/** + * Tests the Db.update() function. + * + * @author dmoebius at scoop dash gmbh dot de + */ +public class UpdateTest { + + private Db db; + + @Before + public void setUp() throws Exception { + db = IciqlSuite.openNewDb(); + db.insertAll(Product.getList()); + db.insertAll(Customer.getList()); + db.insertAll(Order.getList()); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testSimpleUpdate() { + Product p = new Product(); + Product pChang = db.from(p).where(p.productName).is("Chang").selectFirst(); + // update unitPrice from 19.0 to 19.5 + pChang.unitPrice = 19.5; + // update unitsInStock from 17 to 16 + pChang.unitsInStock = 16; + db.update(pChang); + + Product p2 = new Product(); + Product pChang2 = db.from(p2).where(p2.productName).is("Chang").selectFirst(); + assertEquals(19.5, pChang2.unitPrice.doubleValue(), 0.001); + assertEquals(16, pChang2.unitsInStock.intValue()); + + // undo update + pChang.unitPrice = 19.0; + pChang.unitsInStock = 17; + db.update(pChang); + } + + @Test + public void testSimpleUpdateWithCombinedPrimaryKey() { + Order o = new Order(); + Order ourOrder = db.from(o).where(o.orderDate).is(valueOf("2007-01-02")).selectFirst(); + ourOrder.orderDate = valueOf("2007-01-03"); + db.update(ourOrder); + + Order ourUpdatedOrder = db.from(o).where(o.orderDate).is(valueOf("2007-01-03")).selectFirst(); + assertTrue("updated order not found", ourUpdatedOrder != null); + + // undo update + ourOrder.orderDate = valueOf("2007-01-02"); + db.update(ourOrder); + } + + @Test + public void testSimpleMerge() { + Product p = new Product(); + Product pChang = db.from(p).where(p.productName).is("Chang").selectFirst(); + // update unitPrice from 19.0 to 19.5 + pChang.unitPrice = 19.5; + // update unitsInStock from 17 to 16 + pChang.unitsInStock = 16; + db.merge(pChang); + + Product p2 = new Product(); + Product pChang2 = db.from(p2).where(p2.productName).is("Chang").selectFirst(); + assertEquals(19.5, pChang2.unitPrice, 0.001); + assertEquals(16, pChang2.unitsInStock.intValue()); + + // undo update + pChang.unitPrice = 19.0; + pChang.unitsInStock = 17; + db.merge(pChang); + } + + @Test + public void testSimpleMergeWithCombinedPrimaryKey() { + Order o = new Order(); + Order ourOrder = db.from(o).where(o.orderDate).is(valueOf("2007-01-02")).selectFirst(); + ourOrder.orderDate = valueOf("2007-01-03"); + db.merge(ourOrder); + + Order ourUpdatedOrder = db.from(o).where(o.orderDate).is(valueOf("2007-01-03")).selectFirst(); + assertTrue("updated order not found", ourUpdatedOrder != null); + + // undo update + ourOrder.orderDate = valueOf("2007-01-02"); + db.merge(ourOrder); + } + + @Test + public void testSetColumns() { + Product p = new Product(); + Product original = db.from(p).where(p.productId).is(1).selectFirst(); + + // update string and double columns + db.from(p).set(p.productName).to("updated").increment(p.unitPrice).by(3.14).increment(p.unitsInStock) + .by(2).where(p.productId).is(1).update(); + + // confirm the data was properly updated + Product revised = db.from(p).where(p.productId).is(1).selectFirst(); + assertEquals("updated", revised.productName); + assertEquals(original.unitPrice + 3.14, revised.unitPrice, 0.001); + assertEquals(original.unitsInStock + 2, revised.unitsInStock.intValue()); + + // restore the data + db.from(p).set(p.productName).to(original.productName).set(p.unitPrice).to(original.unitPrice) + .increment(p.unitsInStock).by(-2).where(p.productId).is(1).update(); + + // confirm the data was properly restored + Product restored = db.from(p).where(p.productId).is(1).selectFirst(); + assertEquals(original.productName, restored.productName); + assertEquals(original.unitPrice, restored.unitPrice); + assertEquals(original.unitsInStock, restored.unitsInStock); + + double unitPriceOld = db.from(p).where(p.productId).is(1).selectFirst().unitPrice; + // double the unit price + db.from(p).increment(p.unitPrice).by(p.unitPrice).where(p.productId).is(1).update(); + double unitPriceNew = db.from(p).where(p.productId).is(1).selectFirst().unitPrice; + assertEquals(unitPriceOld * 2, unitPriceNew, 0.001); + + } + +} diff --git a/src/test/java/com/iciql/test/UpgradesTest.java b/src/test/java/com/iciql/test/UpgradesTest.java new file mode 100644 index 0000000..7de691f --- /dev/null +++ b/src/test/java/com/iciql/test/UpgradesTest.java @@ -0,0 +1,180 @@ +/*
+ * 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.test;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.Test;
+
+import com.iciql.Db;
+import com.iciql.DbUpgrader;
+import com.iciql.Iciql.IQVersion;
+import com.iciql.test.models.Product;
+import com.iciql.test.models.SupportedTypes;
+import com.iciql.test.models.SupportedTypes.SupportedTypes2;
+
+/**
+ * Tests the database and table upgrade functions.
+ *
+ */
+public class UpgradesTest {
+
+ @Test
+ public void testDatabaseUpgrade() {
+ Db db = IciqlSuite.openNewDb();
+
+ List<Product> products = Product.getList();
+
+ // set the v1 upgrader and insert a record.
+ // this will trigger the upgrade.
+ V1DbUpgrader v1 = new V1DbUpgrader();
+ db.setDbUpgrader(v1);
+ db.insert(products.get(0));
+
+ // confirm that upgrade occurred
+ assertEquals(0, v1.oldVersion.get());
+ assertEquals(1, v1.newVersion.get());
+
+ // open a second connection to the database
+ // and then apply the v2 upgrade.
+ // For H2 its important to keep the first connection
+ // alive so that the database is not destroyed.
+ Db db2 = IciqlSuite.openCurrentDb();
+
+ // set the v2 upgrader and insert a record.
+ // this will trigger the upgrade.
+ V2DbUpgrader v2 = new V2DbUpgrader();
+ db2.setDbUpgrader(v2);
+ db2.insert(products.get(1));
+
+ // confirm that upgrade occurred
+ assertEquals(1, v2.oldVersion.get());
+ assertEquals(2, v2.newVersion.get());
+
+ db.executeUpdate("DROP TABLE iq_versions");
+ db.close();
+ db2.close();
+ }
+
+ @Test
+ public void testDatabaseInheritedUpgrade() {
+ Db db = IciqlSuite.openNewDb();
+
+ List<Product> products = Product.getList();
+
+ // set the v1 upgrader and insert a record.
+ // this will trigger the upgrade.
+ V1DbUpgrader v1 = new V1DbUpgrader();
+ db.setDbUpgrader(v1);
+ db.insert(products.get(0));
+
+ // confirm that upgrade occurred
+ assertEquals(0, v1.oldVersion.get());
+ assertEquals(1, v1.newVersion.get());
+
+ // open a second connection to the database
+ // and then apply the v2 upgrade.
+ // For H2 its important to keep the first connection
+ // alive so that the database is not destroyed.
+ Db db2 = IciqlSuite.openCurrentDb();
+
+ // set the v2 upgrader and insert a record.
+ // this will trigger the upgrade.
+ V2DbUpgraderImpl v2 = new V2DbUpgraderImpl();
+ db2.setDbUpgrader(v2);
+ db2.insert(products.get(1));
+
+ // confirm that upgrade occurred
+ assertEquals(1, v2.oldVersion.get());
+ assertEquals(2, v2.newVersion.get());
+
+ db.executeUpdate("DROP TABLE iq_versions");
+ db.close();
+ db2.close();
+ }
+
+ @Test
+ public void testTableUpgrade() {
+ Db db = IciqlSuite.openNewDb();
+
+ // insert first, this will create version record automatically
+ List<SupportedTypes> original = SupportedTypes.createList();
+ db.insertAll(original);
+
+ // reset the dbUpgrader (clears the update check cache)
+ V2DbUpgrader dbUpgrader = new V2DbUpgrader();
+ db.setDbUpgrader(dbUpgrader);
+
+ SupportedTypes2 s2 = new SupportedTypes2();
+
+ List<SupportedTypes2> types = db.from(s2).select();
+ assertEquals(10, types.size());
+ assertEquals(1, dbUpgrader.oldVersion.get());
+ assertEquals(2, dbUpgrader.newVersion.get());
+ db.executeUpdate("DROP TABLE iq_versions");
+ db.close();
+ }
+
+ /**
+ * A sample database upgrader class.
+ */
+ class BaseDbUpgrader implements DbUpgrader {
+ final AtomicInteger oldVersion = new AtomicInteger(0);
+ final AtomicInteger newVersion = new AtomicInteger(0);
+
+ public boolean upgradeTable(Db db, String schema, String table, int fromVersion, int toVersion) {
+ // just claims success on upgrade request
+ oldVersion.set(fromVersion);
+ newVersion.set(toVersion);
+ return true;
+ }
+
+ public boolean upgradeDatabase(Db db, int fromVersion, int toVersion) {
+ // just claims success on upgrade request
+ oldVersion.set(fromVersion);
+ newVersion.set(toVersion);
+ return true;
+ }
+ }
+
+ /**
+ * A sample V1 database upgrader class.
+ */
+ @IQVersion(1)
+ class V1DbUpgrader extends BaseDbUpgrader {
+ }
+
+ /**
+ * A sample V2 database upgrader class.
+ */
+ @IQVersion(2)
+ class V2DbUpgrader extends BaseDbUpgrader {
+ }
+
+
+ /**
+ * A sample V2 database upgrader class which inherits its
+ * version from the parent class.
+ */
+ @IQVersion()
+ class V2DbUpgraderImpl extends V2DbUpgrader {
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/ViewsTest.java b/src/test/java/com/iciql/test/ViewsTest.java new file mode 100644 index 0000000..be2e085 --- /dev/null +++ b/src/test/java/com/iciql/test/ViewsTest.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012 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.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.iciql.Db; +import com.iciql.test.models.ProductAnnotationOnly; +import com.iciql.test.models.ProductView; +import com.iciql.test.models.ProductViewFromQuery; +import com.iciql.test.models.ProductViewInherited; +import com.iciql.test.models.ProductViewInheritedComplex; +import com.mysql.jdbc.StringUtils; + +/** + * Test annotation processing. + */ +public class ViewsTest { + + /** + * This object represents a database (actually a connection to the + * database). + */ + + private Db db; + + @Before + public void setUp() { + db = IciqlSuite.openNewDb(); + db.insertAll(ProductAnnotationOnly.getList()); + } + + @After + public void tearDown() { + db.close(); + } + + @Test + public void testProductView() { + ProductView view = new ProductView(); + List<ProductView> products = db.from(view).select(); + assertEquals(5, products.size()); + for (int i = 0; i < products.size(); i++) { + assertEquals(3 + i, products.get(i).productId.intValue()); + } + } + + @Test + public void testProductViewInherited() { + ProductViewInherited view = new ProductViewInherited(); + List<ProductViewInherited> products = db.from(view).select(); + assertEquals(5, products.size()); + for (int i = 0; i < products.size(); i++) { + assertEquals(3 + i, products.get(i).productId.intValue()); + } + } + + @Test + public void testComplexInheritance() { + ProductViewInheritedComplex view = new ProductViewInheritedComplex(); + List<ProductViewInheritedComplex> products = db.from(view).select(); + assertEquals(5, products.size()); + for (int i = 0; i < products.size(); i++) { + assertEquals(3 + i, products.get(i).productId.intValue()); + assertTrue(!StringUtils.isNullOrEmpty(products.get(i).productName)); + } + } + + @Test + public void testCreateViewFromQuery() { + // create view from query + ProductAnnotationOnly product = new ProductAnnotationOnly(); + db.from(product).where(product.productId).exceeds(2L).and(product.productId).atMost(7L).createView(ProductViewFromQuery.class); + + // select from the created view + ProductViewFromQuery view = new ProductViewFromQuery(); + List<ProductViewFromQuery> products = db.from(view).select(); + assertEquals(5, products.size()); + for (int i = 0; i < products.size(); i++) { + assertEquals(3 + i, products.get(i).productId.intValue()); + } + + // replace the view + db.from(product).where(product.productId).exceeds(3L).and(product.productId).atMost(8L).replaceView(ProductViewFromQuery.class); + + // select from the replaced view + products = db.from(view).select(); + assertEquals(5, products.size()); + for (int i = 0; i < products.size(); i++) { + assertEquals(4 + i, products.get(i).productId.intValue()); + } + } +} diff --git a/src/test/java/com/iciql/test/models/BooleanModel.java b/src/test/java/com/iciql/test/models/BooleanModel.java new file mode 100644 index 0000000..d22e3c1 --- /dev/null +++ b/src/test/java/com/iciql/test/models/BooleanModel.java @@ -0,0 +1,73 @@ +/*
+ * 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.test.models;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQTable;
+
+/**
+ * Boolean types model.
+ */
+@IQTable(name = "BooleanTest")
+public class BooleanModel {
+
+ @IQColumn(primaryKey = true)
+ public Integer id;
+
+ @IQColumn
+ public Boolean mybool;
+
+ public BooleanModel() {
+ }
+
+ BooleanModel(int id, boolean val) {
+ this.id = id;
+ this.mybool = val;
+ }
+
+ public static List<BooleanModel> getList() {
+ return Arrays.asList(new BooleanModel(1, true), new BooleanModel(2, false),
+ new BooleanModel(3, true), new BooleanModel(4, false));
+ }
+
+ /**
+ * Test boolean as int
+ */
+ @IQTable(name = "BooleanTest")
+ public static class BooleanAsIntModel {
+ @IQColumn(primaryKey = true)
+ public Integer id;
+
+ @IQColumn
+ public Integer mybool;
+
+ public BooleanAsIntModel() {
+ }
+
+ BooleanAsIntModel(int id, boolean val) {
+ this.id = id;
+ this.mybool = val ? 1 : 0;
+ }
+
+ public static List<BooleanAsIntModel> getList() {
+ return Arrays.asList(new BooleanAsIntModel(1, true), new BooleanAsIntModel(2, false),
+ new BooleanAsIntModel(3, true), new BooleanAsIntModel(4, false));
+ }
+ }
+}
diff --git a/src/test/java/com/iciql/test/models/CategoryAnnotationOnly.java b/src/test/java/com/iciql/test/models/CategoryAnnotationOnly.java new file mode 100644 index 0000000..b96ab04 --- /dev/null +++ b/src/test/java/com/iciql/test/models/CategoryAnnotationOnly.java @@ -0,0 +1,70 @@ +/* + * Copyright 2012 Frédéric Gaillard. + * Copyright 2012 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQContraintUnique; +import com.iciql.Iciql.IQTable; + +/** + * A table containing category data. + */ + +@IQTable(name = "AnnotatedCategory", primaryKey = "id") +// @IQIndex(value = "categ", type=IndexType.UNIQUE) +@IQContraintUnique(uniqueColumns = { "categ" }) +public class CategoryAnnotationOnly { + + @IQColumn(name = "id", autoIncrement = true) + public Long categoryId; + + @IQColumn(name = "categ", length = 15, trim = true) + public String category; + + public CategoryAnnotationOnly() { + // public constructor + } + + private CategoryAnnotationOnly(long categoryId, String category) { + this.categoryId = categoryId; + this.category = category; + } + + private static CategoryAnnotationOnly create(int categoryId, String category) { + return new CategoryAnnotationOnly(categoryId, category); + } + + public static List<CategoryAnnotationOnly> getList() { + CategoryAnnotationOnly[] list = { + create(1, "Beverages"), + create(2, "Condiments"), + create(3, "Produce"), + create(4, "Meat/Poultry"), + create(5,"Seafood") + }; + return Arrays.asList(list); + } + + public String toString() { + return category; + } + +} diff --git a/src/test/java/com/iciql/test/models/ComplexObject.java b/src/test/java/com/iciql/test/models/ComplexObject.java new file mode 100644 index 0000000..ce9b9ec --- /dev/null +++ b/src/test/java/com/iciql/test/models/ComplexObject.java @@ -0,0 +1,66 @@ +/* + * 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.test.models; + +import static com.iciql.Define.length; +import static com.iciql.Define.primaryKey; + +import java.math.BigDecimal; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import com.iciql.Iciql; + +/** + * A table containing all possible data types. + */ + +public class ComplexObject implements Iciql { + public Integer id; + public Long amount; + public String name; + public BigDecimal value; + public Date birthday; + public Time time; + public Timestamp created; + + static ComplexObject build(Integer id, boolean isNull) { + ComplexObject obj = new ComplexObject(); + obj.id = id; + obj.amount = isNull ? null : Long.valueOf(1); + obj.name = isNull ? null : "hello"; + obj.value = isNull ? null : new BigDecimal("1"); + obj.birthday = isNull ? null : java.sql.Date.valueOf("2001-01-01"); + obj.time = isNull ? null : Time.valueOf("10:20:30"); + obj.created = isNull ? null : Timestamp.valueOf("2002-02-02 02:02:02"); + return obj; + } + + public void defineIQ() { + primaryKey(id); + length(name, 25); + } + + public static List<ComplexObject> getList() { + return Arrays.asList(new ComplexObject[] { build(0, true), build(1, false) }); + } + +} diff --git a/src/test/java/com/iciql/test/models/Customer.java b/src/test/java/com/iciql/test/models/Customer.java new file mode 100644 index 0000000..ae8e40d --- /dev/null +++ b/src/test/java/com/iciql/test/models/Customer.java @@ -0,0 +1,57 @@ +/*
+ * 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.test.models;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQTable;
+
+/**
+ * A table containing customer data.
+ */
+@IQTable
+public class Customer {
+
+ @IQColumn(length = 25)
+ public String customerId;
+
+ @IQColumn(length = 2)
+ public String region;
+
+ public Customer() {
+ // public constructor
+ }
+
+ public Customer(String customerId, String region) {
+ this.customerId = customerId;
+ this.region = region;
+ }
+
+ public String toString() {
+ return customerId;
+ }
+
+ public static List<Customer> getList() {
+ Customer[] list = { new Customer("ALFKI", "WA"), new Customer("ANATR", "WA"),
+ new Customer("ANTON", "CA") };
+ return Arrays.asList(list);
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/models/DefaultValuesModel.java b/src/test/java/com/iciql/test/models/DefaultValuesModel.java new file mode 100644 index 0000000..cb3b421 --- /dev/null +++ b/src/test/java/com/iciql/test/models/DefaultValuesModel.java @@ -0,0 +1,58 @@ +/*
+ * 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.test.models;
+
+import java.util.Date;
+
+import com.iciql.Iciql.EnumType;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQEnum;
+import com.iciql.Iciql.IQTable;
+import com.iciql.test.models.EnumModels.Tree;
+
+/**
+ * Default values model.
+ */
+@IQTable(name = "DefaultValuesTest")
+public class DefaultValuesModel {
+
+ @IQColumn(primaryKey = true, autoIncrement = true)
+ public Long myLong;
+
+ @SuppressWarnings("deprecation")
+ @IQColumn
+ public Date myDate = new Date(100, 7, 1);
+
+ @IQColumn
+ public Integer myInteger = 12345;
+
+ @IQColumn
+ public Tree myEnumIdTree = Tree.WALNUT;
+
+ @IQColumn
+ @IQEnum(EnumType.NAME)
+ public Tree myNameTree = Tree.MAPLE;
+
+ @IQColumn
+ @IQEnum(EnumType.ORDINAL)
+ public Tree myOrdinalTree = Tree.PINE;
+
+ @IQColumn(nullable = true)
+ public Tree myNullTree;
+
+ public DefaultValuesModel() {
+ }
+}
diff --git a/src/test/java/com/iciql/test/models/EnumModels.java b/src/test/java/com/iciql/test/models/EnumModels.java new file mode 100644 index 0000000..a865f6c --- /dev/null +++ b/src/test/java/com/iciql/test/models/EnumModels.java @@ -0,0 +1,157 @@ +/*
+ * 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.test.models;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.iciql.Iciql.EnumId;
+import com.iciql.Iciql.EnumType;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQEnum;
+import com.iciql.Iciql.IQTable;
+
+/**
+ * Container for reusable enum model classes which exercise the 3 supported
+ * types.
+ */
+public abstract class EnumModels {
+
+ /**
+ * Test of @IQEnum annotated enumeration. This strategy is the default
+ * strategy for all fields of the Tree enum.
+ *
+ * Individual Tree field declarations can override this strategy by
+ * specifying a different @IQEnum annotation.
+ *
+ * Here ORDINAL specifies that this enum will be mapped to an INT column.
+ */
+ @IQEnum(EnumType.ENUMID)
+ public enum Tree implements EnumId {
+ PINE(10), OAK(20), BIRCH(30), WALNUT(40), MAPLE(50);
+
+ private int enumid;
+
+ Tree(int id) {
+ this.enumid = id;
+ }
+
+ @Override
+ public int enumId() {
+ return enumid;
+ }
+ }
+
+ @IQColumn(primaryKey = true)
+ public Integer id;
+
+ public abstract Tree tree();
+
+ /**
+ * Test model for enum-as-enumid.
+ */
+ @IQTable(inheritColumns = true)
+ public static class EnumIdModel extends EnumModels {
+
+ // no need to specify ENUMID type as the enumeration definition
+ // specifies it.
+ @IQColumn
+ private Tree tree;
+
+ public EnumIdModel() {
+ }
+
+ public EnumIdModel(int id, Tree tree) {
+ this.id = id;
+ this.tree = tree;
+ }
+
+ @Override
+ public Tree tree() {
+ return tree;
+ }
+
+ public static List<EnumIdModel> createList() {
+ return Arrays.asList(new EnumIdModel(400, Tree.WALNUT), new EnumIdModel(200, Tree.OAK),
+ new EnumIdModel(500, Tree.MAPLE), new EnumIdModel(300, Tree.BIRCH), new EnumIdModel(100,
+ Tree.PINE));
+ }
+ }
+
+ /**
+ * Test model for enum-as-ordinal.
+ */
+ @IQTable(inheritColumns = true)
+ public static class EnumOrdinalModel extends EnumModels {
+
+ // override the enumtype to ordinal
+ @IQEnum(EnumType.ORDINAL)
+ @IQColumn
+ private Tree tree;
+
+ public EnumOrdinalModel() {
+ }
+
+ public EnumOrdinalModel(int id, Tree tree) {
+ this.id = id;
+ this.tree = tree;
+ }
+
+ @Override
+ public Tree tree() {
+ return tree;
+ }
+
+ public static List<EnumOrdinalModel> createList() {
+ return Arrays.asList(new EnumOrdinalModel(400, Tree.WALNUT), new EnumOrdinalModel(200, Tree.OAK),
+ new EnumOrdinalModel(500, Tree.MAPLE), new EnumOrdinalModel(300, Tree.BIRCH),
+ new EnumOrdinalModel(100, Tree.PINE));
+ }
+ }
+
+ /**
+ * Test model for enum-as-string.
+ */
+ @IQTable(inheritColumns = true)
+ public static class EnumStringModel extends EnumModels {
+
+ // override the enumtype to string
+ // ensure that we specify a length so that the column is VARCHAR
+ @IQEnum(EnumType.NAME)
+ @IQColumn(length = 25)
+ private Tree tree;
+
+ public EnumStringModel() {
+ }
+
+ public EnumStringModel(int id, Tree tree) {
+ this.id = id;
+ this.tree = tree;
+ }
+
+ @Override
+ public Tree tree() {
+ return tree;
+ }
+
+ public static List<EnumStringModel> createList() {
+ return Arrays.asList(new EnumStringModel(400, Tree.WALNUT), new EnumStringModel(200, Tree.OAK),
+ new EnumStringModel(500, Tree.MAPLE), new EnumStringModel(300, Tree.BIRCH),
+ new EnumStringModel(100, Tree.PINE));
+ }
+ }
+}
diff --git a/src/test/java/com/iciql/test/models/MultipleBoolsModel.java b/src/test/java/com/iciql/test/models/MultipleBoolsModel.java new file mode 100644 index 0000000..7bc429c --- /dev/null +++ b/src/test/java/com/iciql/test/models/MultipleBoolsModel.java @@ -0,0 +1,40 @@ +package com.iciql.test.models;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQTable;
+
+/**
+ * Model class to test the runtime exception of too many primitive boolean
+ * fields in the model.
+ *
+ * @author James Moger
+ *
+ */
+@IQTable
+public class MultipleBoolsModel {
+
+ @IQColumn(autoIncrement = true, primaryKey = true)
+ public int id;
+
+ @IQColumn
+ public boolean a;
+
+ @IQColumn
+ public boolean b;
+
+ public MultipleBoolsModel() {
+ }
+
+ public MultipleBoolsModel(boolean a, boolean b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ public static List<MultipleBoolsModel> getList() {
+ return Arrays.asList(new MultipleBoolsModel(true, true), new MultipleBoolsModel(true, false),
+ new MultipleBoolsModel(true, false), new MultipleBoolsModel(false, false));
+ }
+}
\ No newline at end of file diff --git a/src/test/java/com/iciql/test/models/Order.java b/src/test/java/com/iciql/test/models/Order.java new file mode 100644 index 0000000..1fa9097 --- /dev/null +++ b/src/test/java/com/iciql/test/models/Order.java @@ -0,0 +1,73 @@ +/*
+ * 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.test.models;
+
+import static com.iciql.Define.length;
+import static com.iciql.Define.primaryKey;
+import static com.iciql.Define.scale;
+import static com.iciql.Define.tableName;
+
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+
+import com.iciql.Iciql;
+
+/**
+ * A table containing order data.
+ */
+
+public class Order implements Iciql {
+ public String customerId;
+ public Integer orderId;
+ public Date orderDate;
+ public BigDecimal total;
+
+ public Order(String customerId, Integer orderId, String total, String orderDate) {
+ this.customerId = customerId;
+ this.orderId = orderId;
+ this.total = new BigDecimal(total);
+ this.orderDate = java.sql.Date.valueOf(orderDate);
+ }
+
+ public Order() {
+ // public constructor
+ }
+
+ public void defineIQ() {
+ tableName("Orders");
+ length(customerId, 25);
+ length(total, 10);
+ scale(total, 2);
+ primaryKey(customerId, orderId);
+ }
+
+ public static List<Order> getList() {
+ Order[] list = { new Order("ALFKI", 10702, "330.00", "2007-01-02"),
+ new Order("ALFKI", 10952, "471.20", "2007-02-03"),
+ new Order("ANATR", 10308, "88.80", "2007-01-03"),
+ new Order("ANATR", 10625, "479.75", "2007-03-03"),
+ new Order("ANATR", 10759, "320.00", "2007-04-01"),
+ new Order("ANTON", 10365, "403.20", "2007-02-13"),
+ new Order("ANTON", 10682, "375.50", "2007-03-13"),
+ new Order("ANTON", 10355, "480.00", "2007-04-11") };
+ return Arrays.asList(list);
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/models/PrimitivesModel.java b/src/test/java/com/iciql/test/models/PrimitivesModel.java new file mode 100644 index 0000000..44e8b9b --- /dev/null +++ b/src/test/java/com/iciql/test/models/PrimitivesModel.java @@ -0,0 +1,90 @@ +/*
+ * 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.test.models;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQTable;
+import com.iciql.test.IciqlSuite;
+
+/**
+ * Primitive types model.
+ */
+@IQTable(name = "PrimitivesTest")
+public class PrimitivesModel {
+
+ @IQColumn(primaryKey = true)
+ public long myLong;
+
+ @IQColumn
+ public int myInteger;
+
+ @IQColumn
+ public short myShort;
+
+ @IQColumn
+ public byte myByte;
+
+ @IQColumn
+ public boolean myBoolean;
+
+ @IQColumn
+ public double myDouble;
+
+ @IQColumn
+ public float myFloat;
+
+ public PrimitivesModel() {
+ Random rand = new Random();
+ myLong = rand.nextLong();
+ myInteger = rand.nextInt();
+ myShort = (short) rand.nextInt(Short.MAX_VALUE);
+ myByte = (byte) rand.nextInt(Byte.MAX_VALUE);
+ myBoolean = rand.nextInt(1) == 1;
+ myDouble = rand.nextDouble();
+ myFloat = rand.nextFloat();
+ }
+
+ public boolean equivalentTo(PrimitivesModel p) {
+ boolean same = true;
+ same &= myLong == p.myLong;
+ same &= myInteger == p.myInteger;
+ same &= myShort == p.myShort;
+ same &= myByte == p.myByte;
+ same &= myBoolean == p.myBoolean;
+ same &= IciqlSuite.equivalentTo(myDouble, p.myDouble);
+ same &= IciqlSuite.equivalentTo(myFloat, p.myFloat);
+ return same;
+ }
+
+ public static List<PrimitivesModel> getList() {
+ List<PrimitivesModel> list = new ArrayList<PrimitivesModel>();
+ for (int i = 1; i <= 10; i++) {
+ PrimitivesModel p = new PrimitivesModel();
+ p.myLong = i;
+ list.add(p);
+ }
+ return list;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(myLong);
+ }
+}
diff --git a/src/test/java/com/iciql/test/models/Product.java b/src/test/java/com/iciql/test/models/Product.java new file mode 100644 index 0000000..241a3d3 --- /dev/null +++ b/src/test/java/com/iciql/test/models/Product.java @@ -0,0 +1,85 @@ +/*
+ * 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.test.models;
+
+import static com.iciql.Define.index;
+import static com.iciql.Define.length;
+import static com.iciql.Define.primaryKey;
+import static com.iciql.Define.tableName;
+
+import java.util.Arrays;
+import java.util.List;
+
+import com.iciql.Iciql;
+
+/**
+ * A table containing product data.
+ */
+
+public class Product implements Iciql {
+
+ public Integer productId;
+ public String productName;
+ public String category;
+ public Double unitPrice;
+ public Integer unitsInStock;
+
+ public Product() {
+ // public constructor
+ }
+
+ private Product(int productId, String productName, String category, double unitPrice, int unitsInStock) {
+ this.productId = productId;
+ this.productName = productName;
+ this.category = category;
+ this.unitPrice = unitPrice;
+ this.unitsInStock = unitsInStock;
+ }
+
+ public void defineIQ() {
+ tableName("Product");
+ primaryKey(productId);
+ length(productName, 255);
+ length(category, 255);
+ index("MyIndex", IndexType.STANDARD, productName, category);
+ }
+
+ private static Product create(int productId, String productName, String category, double unitPrice,
+ int unitsInStock) {
+ return new Product(productId, productName, category, unitPrice, unitsInStock);
+ }
+
+ public static List<Product> getList() {
+ Product[] list = { create(1, "Chai", "Beverages", 18, 39), create(2, "Chang", "Beverages", 19.0, 17),
+ create(3, "Aniseed Syrup", "Condiments", 10.0, 13),
+ create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53),
+ create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0),
+ create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120),
+ create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15),
+ create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6),
+ create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29),
+ create(10, "Ikura", "Seafood", 31.0, 31), };
+
+ return Arrays.asList(list);
+ }
+
+ public String toString() {
+ return productName + ": " + unitsInStock;
+ }
+
+}
diff --git a/src/test/java/com/iciql/test/models/ProductAnnotationOnly.java b/src/test/java/com/iciql/test/models/ProductAnnotationOnly.java new file mode 100644 index 0000000..1f6b4e2 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductAnnotationOnly.java @@ -0,0 +1,94 @@ +/* + * 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQIndex; +import com.iciql.Iciql.IQIndexes; +import com.iciql.Iciql.IQTable; +import com.iciql.Iciql.IndexType; + +/** + * A table containing product data. + */ + +@IQTable(name = "AnnotatedProduct", primaryKey = "id") +@IQIndexes({ @IQIndex({ "name", "cat" }), @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") }) +public class ProductAnnotationOnly { + + public String unmappedField; + + @IQColumn(name = "id", autoIncrement = true) + public Long productId; + + @IQColumn(name = "cat", length = 15, trim = true) + public String category; + + @IQColumn(name = "name", length = 50) + public String productName; + + @SuppressWarnings("unused") + @IQColumn + private Double unitPrice; + + @IQColumn + private Integer unitsInStock; + + public ProductAnnotationOnly() { + // public constructor + } + + private ProductAnnotationOnly(long productId, String productName, String category, double unitPrice, + int unitsInStock, String unmappedField) { + this.productId = productId; + this.productName = productName; + this.category = category; + this.unitPrice = unitPrice; + this.unitsInStock = unitsInStock; + this.unmappedField = unmappedField; + } + + private static ProductAnnotationOnly create(int productId, String productName, String category, + double unitPrice, int unitsInStock, String unmappedField) { + return new ProductAnnotationOnly(productId, productName, category, unitPrice, unitsInStock, + unmappedField); + } + + public static List<ProductAnnotationOnly> getList() { + String unmappedField = "unmapped"; + ProductAnnotationOnly[] list = { create(1, "Chai", "Beverages", 18, 39, unmappedField), + create(2, "Chang", "Beverages", 19.0, 17, unmappedField), + create(3, "Aniseed Syrup", "Condiments", 10.0, 13, unmappedField), + create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53, unmappedField), + create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0, unmappedField), + create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120, unmappedField), + create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15, unmappedField), + create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6, unmappedField), + create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29, unmappedField), + create(10, "Ikura", "Seafood", 31.0, 31, unmappedField), }; + return Arrays.asList(list); + } + + public String toString() { + return productName + ": " + unitsInStock; + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductAnnotationOnlyWithForeignKey.java b/src/test/java/com/iciql/test/models/ProductAnnotationOnlyWithForeignKey.java new file mode 100644 index 0000000..4268a89 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductAnnotationOnlyWithForeignKey.java @@ -0,0 +1,102 @@ +/* + * Copyright 2012 Frédéric Gaillard. + * Copyright 2012 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Iciql.ConstraintDeleteType; +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQContraintForeignKey; +import com.iciql.Iciql.IQIndex; +import com.iciql.Iciql.IQIndexes; +import com.iciql.Iciql.IQTable; +import com.iciql.Iciql.IndexType; + +/** + * A table containing product data. + */ + +@IQTable(name = "AnnotatedProduct", primaryKey = "id") +@IQIndexes({ @IQIndex({ "name", "cat" }), @IQIndex(name = "nameidx", type = IndexType.HASH, value = "name") }) +@IQContraintForeignKey( + foreignColumns= { "cat" }, + referenceName = "AnnotatedCategory", + referenceColumns = { "categ" }, + deleteType = ConstraintDeleteType.CASCADE +) +public class ProductAnnotationOnlyWithForeignKey { + + public String unmappedField; + + @IQColumn(name = "id", autoIncrement = true) + public Long productId; + + @IQColumn(name = "cat", length = 15, trim = true) + public String category; + + @IQColumn(name = "name", length = 50) + public String productName; + + @SuppressWarnings("unused") + @IQColumn + private Double unitPrice; + + @IQColumn + private Integer unitsInStock; + + public ProductAnnotationOnlyWithForeignKey() { + // public constructor + } + + private ProductAnnotationOnlyWithForeignKey(long productId, String productName, String category, double unitPrice, + int unitsInStock, String unmappedField) { + this.productId = productId; + this.productName = productName; + this.category = category; + this.unitPrice = unitPrice; + this.unitsInStock = unitsInStock; + this.unmappedField = unmappedField; + } + + private static ProductAnnotationOnlyWithForeignKey create(int productId, String productName, String category, + double unitPrice, int unitsInStock, String unmappedField) { + return new ProductAnnotationOnlyWithForeignKey(productId, productName, category, unitPrice, unitsInStock, + unmappedField); + } + + public static List<ProductAnnotationOnlyWithForeignKey> getList() { + String unmappedField = "unmapped"; + ProductAnnotationOnlyWithForeignKey[] list = { create(1, "Chai", "Beverages", 18, 39, unmappedField), + create(2, "Chang", "Beverages", 19.0, 17, unmappedField), + create(3, "Aniseed Syrup", "Condiments", 10.0, 13, unmappedField), + create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53, unmappedField), + create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0, unmappedField), + create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120, unmappedField), + create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15, unmappedField), + create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6, unmappedField), + create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29, unmappedField), + create(10, "Ikura", "Seafood", 31.0, 31, unmappedField), }; + return Arrays.asList(list); + } + + public String toString() { + return productName + ": " + unitsInStock; + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductInheritedAnnotation.java b/src/test/java/com/iciql/test/models/ProductInheritedAnnotation.java new file mode 100644 index 0000000..112f4ef --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductInheritedAnnotation.java @@ -0,0 +1,64 @@ +/* + * 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Iciql.IQTable; + +/** + * This class inherits all its fields from a parent class which has annotated + * columns. The IQTable annotation of the parent class is ignored and only the + * IQTable annotation of this class matters. However, this table inherits + * IQColumns from its super class. + */ +@IQTable(inheritColumns = true, annotationsOnly = false) +public class ProductInheritedAnnotation extends ProductMixedAnnotation { + + public ProductInheritedAnnotation() { + // public constructor + } + + private ProductInheritedAnnotation(int productId, String productName, String category, double unitPrice, + int unitsInStock, String mappedField) { + super(productId, productName, category, unitPrice, unitsInStock, mappedField); + } + + private static ProductInheritedAnnotation create(int productId, String productName, String category, + double unitPrice, int unitsInStock, String mappedField) { + return new ProductInheritedAnnotation(productId, productName, category, unitPrice, unitsInStock, + mappedField); + } + + public static List<ProductInheritedAnnotation> getData() { + String mappedField = "mapped"; + ProductInheritedAnnotation[] list = { create(1, "Chai", "Beverages", 18, 39, mappedField), + create(2, "Chang", "Beverages", 19.0, 17, mappedField), + create(3, "Aniseed Syrup", "Condiments", 10.0, 13, mappedField), + create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53, mappedField), + create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0, mappedField), + create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120, mappedField), + create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15, mappedField), + create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6, mappedField), + create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29, mappedField), + create(10, "Ikura", "Seafood", 31.0, 31, mappedField), }; + return Arrays.asList(list); + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductMixedAnnotation.java b/src/test/java/com/iciql/test/models/ProductMixedAnnotation.java new file mode 100644 index 0000000..a893a69 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductMixedAnnotation.java @@ -0,0 +1,104 @@ +/* + * 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Define; +import com.iciql.Iciql; +import com.iciql.Iciql.IQIndex; +import com.iciql.Iciql.IQTable; + +/** + * A table containing product data. + */ + +@IQTable(annotationsOnly = false) +@IQIndex({ "name", "cat" }) +public class ProductMixedAnnotation implements Iciql { + + public Double unitPrice; + public Integer unitsInStock; + public String mappedField; + + @IQIgnore + public String productDescription; + + @IQColumn(name = "cat", length = 255) + public String category; + + @IQColumn(name = "id", primaryKey = true) + private Integer productId; + + @IQColumn(name = "name", length = 255) + private String productName; + + public ProductMixedAnnotation() { + // public constructor + } + + protected ProductMixedAnnotation(int productId, String productName, String category, double unitPrice, + int unitsInStock, String mappedField) { + this.productId = productId; + this.productName = productName; + this.category = category; + this.unitPrice = unitPrice; + this.unitsInStock = unitsInStock; + this.mappedField = mappedField; + this.productDescription = category + ": " + productName; + } + + private static ProductMixedAnnotation create(int productId, String productName, String category, + double unitPrice, int unitsInStock, String mappedField) { + return new ProductMixedAnnotation(productId, productName, category, unitPrice, unitsInStock, + mappedField); + } + + public static List<ProductMixedAnnotation> getList() { + String mappedField = "mapped"; + ProductMixedAnnotation[] list = { create(1, "Chai", "Beverages", 18, 39, mappedField), + create(2, "Chang", "Beverages", 19.0, 17, mappedField), + create(3, "Aniseed Syrup", "Condiments", 10.0, 13, mappedField), + create(4, "Chef Anton's Cajun Seasoning", "Condiments", 22.0, 53, mappedField), + create(5, "Chef Anton's Gumbo Mix", "Condiments", 21.3500, 0, mappedField), + create(6, "Grandma's Boysenberry Spread", "Condiments", 25.0, 120, mappedField), + create(7, "Uncle Bob's Organic Dried Pears", "Produce", 30.0, 15, mappedField), + create(8, "Northwoods Cranberry Sauce", "Condiments", 40.0, 6, mappedField), + create(9, "Mishi Kobe Niku", "Meat/Poultry", 97.0, 29, mappedField), + create(10, "Ikura", "Seafood", 31.0, 31, mappedField), }; + return Arrays.asList(list); + } + + public String toString() { + return productName + ": " + unitsInStock; + } + + public int id() { + return productId; + } + + public String name() { + return productName; + } + + @Override + public void defineIQ() { + Define.length(mappedField, 25); + } +} diff --git a/src/test/java/com/iciql/test/models/ProductNoCreateTable.java b/src/test/java/com/iciql/test/models/ProductNoCreateTable.java new file mode 100644 index 0000000..cbf96e9 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductNoCreateTable.java @@ -0,0 +1,59 @@ +/* + * 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.test.models; + +import java.util.Arrays; +import java.util.List; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQTable; + +/** + * A table containing product data. + */ + +@IQTable(create = false) +public class ProductNoCreateTable { + + @SuppressWarnings("unused") + @IQColumn(name = "id") + private Integer productId; + + @SuppressWarnings("unused") + @IQColumn(name = "name") + private String productName; + + public ProductNoCreateTable() { + // public constructor + } + + private ProductNoCreateTable(int productId, String productName) { + this.productId = productId; + this.productName = productName; + } + + private static ProductNoCreateTable create(int productId, String productName) { + return new ProductNoCreateTable(productId, productName); + } + + public static List<ProductNoCreateTable> getList() { + ProductNoCreateTable[] list = { create(1, "Chai"), create(2, "Chang") }; + return Arrays.asList(list); + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductView.java b/src/test/java/com/iciql/test/models/ProductView.java new file mode 100644 index 0000000..2efe9eb --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductView.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012 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.test.models; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQConstraint; +import com.iciql.Iciql.IQView; + +/** + * A view containing product data. + */ + +@IQView(name = "AnnotatedProductView", tableName = "AnnotatedProduct") +public class ProductView { + + public String unmappedField; + + @IQColumn(name = "id", autoIncrement = true) + @IQConstraint("this <= 7 AND this > 2") + public Long productId; + + @IQColumn(name = "name") + public String productName; + + public ProductView() { + // public constructor + } + + public String toString() { + return productName + " (" + productId + ")"; + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductViewFromQuery.java b/src/test/java/com/iciql/test/models/ProductViewFromQuery.java new file mode 100644 index 0000000..2f2f194 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductViewFromQuery.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012 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.test.models; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQView; + +/** + * A view containing product data. + */ + +@IQView(name = "AnnotatedProductViewInherited", inheritColumns = true) +public class ProductViewFromQuery extends ProductAnnotationOnly { + + public String unmappedField; + + @IQColumn(name = "id") + public Long productId; + + public ProductViewFromQuery() { + // public constructor + } + + public String toString() { + return productName + " (" + productId + ")"; + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductViewInherited.java b/src/test/java/com/iciql/test/models/ProductViewInherited.java new file mode 100644 index 0000000..e9c274b --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductViewInherited.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012 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.test.models; + +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQConstraint; +import com.iciql.Iciql.IQView; + +/** + * A view containing product data. + */ + +@IQView(name = "AnnotatedProductViewInherited", inheritColumns = true) +public class ProductViewInherited extends ProductAnnotationOnly { + + public String unmappedField; + + @IQColumn(name = "id", autoIncrement = true) + @IQConstraint("this <= 7 AND this > 2") + public Long productId; + + public ProductViewInherited() { + // public constructor + } + + public String toString() { + return productName + " (" + productId + ")"; + } + +} diff --git a/src/test/java/com/iciql/test/models/ProductViewInheritedComplex.java b/src/test/java/com/iciql/test/models/ProductViewInheritedComplex.java new file mode 100644 index 0000000..55e7ba8 --- /dev/null +++ b/src/test/java/com/iciql/test/models/ProductViewInheritedComplex.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012 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.test.models; + +import com.iciql.Iciql.IQView; + +/** + * A view containing product data. + */ + +@IQView(inheritColumns = true) +public class ProductViewInheritedComplex extends ProductViewInherited { + +} diff --git a/src/test/java/com/iciql/test/models/StaticQueries.java b/src/test/java/com/iciql/test/models/StaticQueries.java new file mode 100644 index 0000000..09f84e6 --- /dev/null +++ b/src/test/java/com/iciql/test/models/StaticQueries.java @@ -0,0 +1,87 @@ +/*
+ * 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.test.models;
+
+import java.sql.Timestamp;
+
+import com.iciql.Iciql.EnumType;
+import com.iciql.Iciql.IQColumn;
+import com.iciql.Iciql.IQEnum;
+import com.iciql.Iciql.IQTable;
+import com.iciql.test.models.EnumModels.Tree;
+
+/**
+ * Static query models.
+ */
+public class StaticQueries {
+
+ @IQTable(name = "StaticQueryTest1")
+ public static class StaticModel1 {
+
+ @IQColumn(primaryKey = true, autoIncrement = true)
+ public Integer id;
+
+ @IQColumn
+ @IQEnum(EnumType.NAME)
+ public Tree myTree;
+
+ @IQColumn
+ public String myString;
+
+ @IQColumn
+ public Boolean myBool;
+
+ @IQColumn
+ public Timestamp myTimestamp;
+
+ @IQColumn
+ public java.sql.Date myDate;
+
+ @IQColumn
+ public java.sql.Time myTime;
+
+ public StaticModel1() {
+ }
+ }
+
+ @IQTable(name = "StaticQueryTest2")
+ public static class StaticModel2 {
+
+ @IQColumn(primaryKey = true, autoIncrement = true)
+ public Integer id;
+
+ @IQColumn
+ @IQEnum(EnumType.ENUMID)
+ public Tree myTree;
+
+ public StaticModel2() {
+ }
+ }
+
+ @IQTable(name = "StaticQueryTest3")
+ public static class StaticModel3 {
+
+ @IQColumn(primaryKey = true, autoIncrement = true)
+ public Integer id;
+
+ @IQColumn
+ @IQEnum(EnumType.ORDINAL)
+ public Tree myTree;
+
+ public StaticModel3() {
+ }
+ }
+}
diff --git a/src/test/java/com/iciql/test/models/SupportedTypes.java b/src/test/java/com/iciql/test/models/SupportedTypes.java new file mode 100644 index 0000000..1aaa833 --- /dev/null +++ b/src/test/java/com/iciql/test/models/SupportedTypes.java @@ -0,0 +1,199 @@ +/* + * 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.test.models; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import com.iciql.Iciql.EnumType; +import com.iciql.Iciql.IQColumn; +import com.iciql.Iciql.IQEnum; +import com.iciql.Iciql.IQIndex; +import com.iciql.Iciql.IQIndexes; +import com.iciql.Iciql.IQTable; +import com.iciql.Iciql.IQVersion; +import com.iciql.Iciql.IndexType; +import com.iciql.test.IciqlSuite; +import com.iciql.test.models.EnumModels.Tree; +import com.iciql.util.Utils; + +/** + * A data class that contains a column for each data type. + */ +@IQTable +@IQIndexes({ @IQIndex({ "myLong", "myInteger" }), @IQIndex(type = IndexType.HASH, value = "myString") }) +@IQVersion(1) +public class SupportedTypes { + + public static final SupportedTypes SAMPLE = new SupportedTypes(); + + /** + * Test of plain enumeration. + * + * Each field declaraton of this enum must specify a mapping strategy. + */ + public enum Flower { + ROSE, TULIP, MUM, PETUNIA, MARIGOLD, DAFFODIL; + } + + @IQColumn(primaryKey = true, autoIncrement = true) + public Integer id; + + @IQColumn + private Boolean myBool; + + @IQColumn + private Byte myByte; + + @IQColumn + private Short myShort; + + @IQColumn + private Integer myInteger; + + @IQColumn + private Long myLong; + + @IQColumn + private Float myFloat; + + @IQColumn + private Double myDouble; + + // scale change must match the test value scale + @IQColumn(length = 10, scale = 5) + private BigDecimal myBigDecimal; + + @IQColumn(length = 40) + private String myString; + + @IQColumn + private java.util.Date myUtilDate; + + @IQColumn + private java.sql.Date mySqlDate; + + @IQColumn + private java.sql.Time mySqlTime; + + @IQColumn + private java.sql.Timestamp mySqlTimestamp; + + @IQColumn + private byte[] myBlob; + + // test default enum type NAME + @IQColumn(trim = true, length = 25) + private Flower myDefaultFlower; + + @IQEnum(EnumType.NAME) + @IQColumn(trim = true, length = 25) + private Flower myFavoriteFlower; + + @IQEnum(EnumType.ORDINAL) + @IQColumn + private Flower myOtherFavoriteFlower; + + @IQEnum(EnumType.ORDINAL) + @IQColumn + // override the default enum strategy and use the ordinal value + private Tree myFavoriteTree; + + // @IQEnum is set on the enumeration definition and is shared + // by all uses of Tree as an @IQColumn + @IQColumn + private Tree myOtherFavoriteTree; + + public static List<SupportedTypes> createList() { + List<SupportedTypes> list = Utils.newArrayList(); + long now = System.currentTimeMillis(); + long oneday = 24 * 60 * 60 * 1000L; + for (int i = 0; i < 10; i++) { + list.add(randomValue(now - (i * oneday))); + } + return list; + } + + static SupportedTypes randomValue(long time) { + Random rand = new Random(); + SupportedTypes s = new SupportedTypes(); + s.myBool = new Boolean(rand.nextBoolean()); + s.myByte = new Byte((byte) rand.nextInt(Byte.MAX_VALUE)); + s.myShort = new Short((short) rand.nextInt(Short.MAX_VALUE)); + s.myInteger = new Integer(rand.nextInt()); + s.myLong = new Long(rand.nextLong()); + s.myFloat = new Float(rand.nextFloat()); + s.myDouble = new Double(rand.nextDouble()); + s.myBigDecimal = new BigDecimal(rand.nextDouble()); + // scale must match annotation + s.myBigDecimal = s.myBigDecimal.setScale(5, RoundingMode.UP); + s.myString = Long.toHexString(rand.nextLong()); + s.myUtilDate = new java.util.Date(time); + s.mySqlDate = new java.sql.Date(time); + s.mySqlTime = new java.sql.Time(time); + s.mySqlTimestamp = new java.sql.Timestamp(time); + s.myBlob = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + s.myDefaultFlower = Flower.DAFFODIL; + s.myFavoriteFlower = Flower.MUM; + s.myOtherFavoriteFlower = Flower.MARIGOLD; + s.myFavoriteTree = Tree.BIRCH; + s.myOtherFavoriteTree = Tree.WALNUT; + return s; + } + + public boolean equivalentTo(SupportedTypes s) { + boolean same = true; + same &= myBool.equals(s.myBool); + same &= myByte.equals(s.myByte); + same &= myShort.equals(s.myShort); + same &= myInteger.equals(s.myInteger); + same &= myLong.equals(s.myLong); + same &= IciqlSuite.equivalentTo(myFloat, s.myFloat); + same &= IciqlSuite.equivalentTo(myDouble, s.myDouble); + same &= myBigDecimal.compareTo(s.myBigDecimal) == 0; + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + same &= df.format(myUtilDate).equals(df.format(s.myUtilDate)); + same &= df.format(mySqlTimestamp).equals(df.format(s.mySqlTimestamp)); + same &= mySqlDate.toString().equals(s.mySqlDate.toString()); + same &= mySqlTime.toString().equals(s.mySqlTime.toString()); + same &= myString.equals(s.myString); + same &= Arrays.equals(myBlob, s.myBlob); + same &= myDefaultFlower.equals(s.myDefaultFlower); + same &= myFavoriteFlower.equals(s.myFavoriteFlower); + same &= myOtherFavoriteFlower.equals(s.myOtherFavoriteFlower); + same &= myFavoriteTree.equals(s.myFavoriteTree); + same &= myOtherFavoriteTree.equals(s.myOtherFavoriteTree); + return same; + } + + /** + * This class demonstrates the table upgrade. + */ + @IQTable(name = "SupportedTypes", inheritColumns = true) + @IQVersion(2) + public static class SupportedTypes2 extends SupportedTypes { + + public SupportedTypes2() { + // nothing to do + } + } +} |