Browse Source

Drop site sources from project in favor of wiki repo

tags/release-2.1.0
James Moger 8 years ago
parent
commit
520d49f6f2

+ 0
- 173
build.xml View File

@@ -95,177 +95,4 @@

</target>


<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Build the iciql website
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
<target name="buildSite" description="Build the iciql website">
<!-- ensure we have performance data -->
<mx:if>
<not>
<available file="${project.outputDirectory}/performance_db.txt" />
</not>
<then>
<fail message="Please run the &quot;testsuite&quot; target!"/>
</then>
</mx:if>

<!-- Download links -->
<property name="gc.url" value="http://gitblit.github.io/iciql/maven/com/iciql/${project.artifactId}/${project.releaseVersion}/" />
<property name="releaselog" value="${basedir}/releases.moxie" />

<mx:doc googleplusone="true" prettifyTheme="googlecode" minify="true"
templateDir="${project.siteSourceDirectory}/templates"
customless="custom.less" rssFeed="rss.xml" atomFeed="atom.xml">

<logo file="iciql_white.png" />
<favicon file="iciql-favicon.png" />

<load token="%DBPERFORMANCE%" file="${project.outputDirectory}/performance_db.txt" />
<regex searchPattern="\b(issue)(\s*[#]?|-){0,1}(\d+)\b"
replacePattern="&lt;a href='${project.issuesUrl}/detail?id=$3'&gt;issue $3&lt;/a&gt;" />

<structure>

<menu name="about" pager="true" pagerPlacement="bottom" pagerLayout="justified">
<page name="overview" src="index.mkd" out="index.html" />
<page name="performance" src="performance.mkd" out="performance.html" />
<page name="jaqu comparison" src="jaqu_comparison.mkd" out="jaqu_comparison.html" />
</menu>

<menu name="getting started" pager="true" pagerPlacement="bottom" pagerLayout="justified">
<page name="table model classes" src="model_classes.mkd" out="model_classes.html" headerLinks="true" />
<page name="data type adapters (DTA)" src="dta.mkd" out="dta.html" headerLinks="true" />
<page name="data access object (DAO) usage" src="dao.mkd" out="dao.html" headerLinks="true" />
<page name="database and table versioning" src="table_versioning.mkd" out="table_versioning.html" headerLinks="true" />
<divider />
<page name="SQL DSL usage" src="usage.mkd" out="usage.html" headerLinks="true" />
<page name="SQL DSL examples" src="examples.mkd" out="examples.html" headerLinks="true" />
<page name="tools" src="tools.mkd" out="tools.html" headerLinks="true" />
</menu>

<page name="building" src="building.mkd" out="building.html" />

<page name="release notes" out="releasenotes.html">
<template src="releasecurrent.ftl" data="${releaselog}" />
</page>
<page out="releases.html" navbarlink="false">
<template src="releasehistory.ftl" data="${releaselog}" />
</page>

<menu name="downloads">
<link name="Maven Central (2.0.0+)"
src="http://search.maven.org/#search|ga|1|com.gitblit.iciql" />
<divider />
<link name="Iciql Maven Repository (pre-2.0.0)" src="${project.mavenUrl}" />
</menu>

<menu name="links">
<link name="Github" src="${project.scmUrl}" />
<link name="Issues" src="${project.issuesUrl}" />
</menu>
<divider />
</structure>

<!-- Generate RSS and Atom feeds from the release history -->
<page as="atom.xml">
<template src="atom.ftl" data="${releaselog}" />
</page>
<page as="rss.xml">
<template src="rss.ftl" data="${releaselog}" />
</page>

</mx:doc>

<!-- Copy standard javadoc -->
<mkdir dir="${project.siteTargetDirectory}/javadoc" />
<copy todir="${project.siteTargetDirectory}/javadoc">
<fileset dir="${project.javadocTargetDirectory}" />
</copy>
</target>


<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Copy the built site to the gh-pages branch
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
<target name="updateGhpages" depends="buildSite">
<mx:ghpages obliterate="false" />
</target>


<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Publish site to hosting service
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
<target name="publishSite" depends="updateGhpages" description="Publish the iciql site to a webserver" >

<echo>Uploading ${project.artifactId} ${project.version} website</echo>

<mx:ftp server="${ftp.server}"
userid="${ftp.user}"
password="${ftp.password}"
remotedir="${ftp.site.dir}"
passive="true"
verbose="yes">
<fileset dir="${project.siteTargetDirectory}" />
</mx:ftp>
</target>


<!--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tag a new version and prepare for the next development cycle.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-->
<target name="tagRelease" depends="prepare" description="Tags a release">
<!-- release -->
<property name="dryrun" value="false" />
<mx:version stage="release" dryrun="${dryrun}" />
<property name="project.tag" value="v${project.version}" />
<!-- commit build.moxie & releases.moxie (automatic) -->
<mx:commit showtitle="no">
<message>Prepare ${project.version} release</message>
<tag name="${project.tag}">
<message>${project.name} ${project.version} release</message>
</tag>
</mx:commit>

<!-- create the release process script -->
<mx:if>
<os family="windows" />
<then>
<!-- Windows PowerShell script -->
<!-- set-executionpolicy remotesigned -->
<property name="recipe" value="release_${project.version}.ps1" />
</then>
<else>
<!-- Bash script -->
<property name="recipe" value="release_${project.version}.sh" />
</else>
</mx:if>
<delete file="${recipe}" failonerror="false" quiet="true" verbose="false" />
<!-- Work-around for lack of proper ant property substitution in copy -->
<property name="dollar" value="$"/>
<copy file="release.template" tofile="${recipe}">
<filterset begintoken="${dollar}{" endtoken="}">
<filter token="project.version" value="${project.version}" />
<filter token="project.commitId" value="${project.commitId}" />
<filter token="project.tag" value="${project.tag}" />
</filterset>
</copy>
<chmod file="${recipe}" perm="ugo+rx" />

<!-- next cycle -->
<mx:version stage="snapshot" incrementNumber="minor" dryrun="${dryrun}" />
<mx:commit showtitle="no">
<message>Reset build identifiers for next development cycle</message>
</mx:commit>
</target>


</project>

+ 0
- 28
src/site/building.mkd View File

@@ -1,28 +0,0 @@
## Building from Source
### Maven
You may use Maven to build the project:
mvn clean package
You may use Maven to run the test suite on the default database:
mvn clean test
### Ant
You may use Ant to build this project:
ant clean build
You may execute the full test suite against all tested databases:
ant testsuite
## 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"

+ 0
- 55
src/site/custom.less View File

@@ -1,55 +0,0 @@
// GLOBAL VALUES
// --------------------------------------------------
@standardGray: #ccc;
@iciql: #95C7F9;
@white: #fff;
// Dropdown
// -------------------------
@dropdownLinkBackgroundHover: @iciql;
// Navbar
// -------------------------
@navbarHeight: 50px;
@navbarBackground: @iciql;
@navbarBackgroundHighlight: @iciql;
@navbarText: @white;
@navbarLinkColor: @white;
@navbarLinkColorHover: @white;
@navbarLinkColorActive: @white;
@navbarLinkBackgroundHover: transparent;
@navbarLinkBackgroundActive: transparent;
.navbar {
.brand {
@elementHeight: 48px;
padding: 5px;
}
}
.navbar .nav > li > a {
font-size: @baseFontSize + 1;
text-shadow: 0 1px 0 #6b94df;
}
.navbar .nav > li > a:hover {
text-shadow: 0 0 1em white;
}
.navbar .nav > .active > a,
.navbar .nav > .active > a:hover,
.navbar .nav > .active > a:focus {
box-shadow: none;
text-decoration: underline;
}
.dropdown-submenu > a:after {
margin-right: -5px;
}
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; }

+ 0
- 180
src/site/dao.mkd View File

@@ -1,180 +0,0 @@
## Data Access Object (DAO)
[JDBI](http://jdbi.org) brings an interesting feature to the table with dynamic generation of an annotation-based, partially type-safe DAO. This is a great idea and one that Iciql has absorbed into it's featureset.
The Iciql implementation is quite different, but the usage is very similar. Iciql does not aim to recreate all features and capabilities of JDBI's DAO.
### Instantiating a DAO
Once you have a Db instance, you may generate a dynamic DAO instance which is backed by it.
---JAVA---
Db db = Db.open("jdbc:h2:mem:iciql");
db.open(MyDao.class);
---JAVA---
A minimal DAO is an *interface* that extends the `Dao` interface. This gives your DAO instance access to the standard Iciql CRUD methods for interacting with your database models, the `db()` method to retrieve the underlying db instance, and the `close()` method for closing the underlying JDBC connection.
---JAVA---
public interface MyDao extends Dao {
}
---JAVA---
Your `Dao` instance is also auto-closable so you may use the Java 7 try-with-resources syntax.
**Note:** You never implement the DAO methods - that is taken care of for you through the magic of `java.lang.reflect.Proxy` and `com.iciql.DaoProxy`.
### @SqlQuery
DAO queries are method declarations annotated with `@SqlQuery`.
#### Return types
1. An `@SqlQuery` method must specify a non-void return a type.
2. The return type may not be a `java.util.Collection`, but it may be an array [] type. This is due to generic type erasure by javac whereas arrays preserve their component type information.
**NOTE:** Iciql will always return a 0-length array instead of a null when there are no results so you won't have to worry about null checks.
3. An `@SqlQuery` method may specify a data type adapter using the `@TypeAdapter` annotation if the returned value is a field, not a row.
##### Returning a field with @TypeAdapter
Normally, Iciql will map the fields in a query ResultSet to your return type object. However, if you are querying a single field from a table then you may specify a `@TypeAdapter` on an `@SqlQuery` method allowing you to deserialize complex data into an object.
For example, if you are using the Postgres JSON/JSONB column type in your table then you might want to directly deserialize the raw JSON stored in Postgres into an object rather than just retrieving the JSON document and manually transforming it. You can use a `@TypeAdapter` to perform this work for you.
#### Method Argument->Statement Parameter mapping
`@SqlQuery` supports 6 techniques for mapping method arguments to statement parameters.
1. `:?` where the method argument order implicitly determines statement parameter order. This is similar to a PreparedStatement.
2. `:arg0` where you specify the 0-based index of the method argument.
3. `:1` where you specify the 1-based index of the method argument.
4. `:name` automatic Java 8 method parameter naming, assuming you are compiling on Java 8 with the `-parameters` javac flag.
5. `@Bind("name") + :name` argument annotation where you explicitly name the statement parameter.
6. `@BindBean("prefix") + :prefix.property` argument annotation which flags the argument as a JavaBean. This allows you to access JavaBean properties from your statement.
**NOTE:** If the prefix is empty, your JavaBean properties will be directly accessible. (e.g. `:property` not `:p.property`)
#### Example @SqlQuery usage
---JAVA---
public interface MyDao extends Dao {
@SqlQuery("select * from Product")
Product [] getAllProducts();
// Named parameters
@SqlQuery("select * from Product where productId = :id")
Product getProduct(@Bind("id") long id);
// Reflection-style 0-indexed args
@SqlQuery("select * from Product where productId = :arg0")
Product getProduct2(long id);
// JDBC-style 1-indexed parameters
@SqlQuery("select * from Product where productId = :1")
Product getProduct2(long id);
// If you are compiling on Java 8 with -parameters
@SqlQuery("select * from Product where productId = :id")
Product getProduct2(long id);
// demonstrates how to use bean binding
@SqlQuery("select productId from Product where category = :p.category and unitsInStock >= :p.unitsInStock")
long [] getSimilarInStockItemIds(@BindBean("p") Product p);
// You can extract a field with full standard type mapping
@SqlQuery("select orderDate from Orders order by orderDate desc limit 1")
Date getMostRecentOrderDate();
// You can extract a field that requires a data type adapter (e.g. a Postgres JSON/JSONB, BLOB, etc)
@SqlQuery("select invoice from Invoices order by received desc limit 1")
@TypeAdapter(InvoiceAdapterImpl.class)
Invoice getMostRecentInvoice();
}
---JAVA---
### @SqlStatement
DAO statements are method declarations annotated with `@SqlStatement`.
#### Return types
Statements to now return a ResultSet so `@SqlStatement` methods have three acceptable return types:
1. *void*
2. *boolean*, if the affected row count is non-zero, true is returned, otherwise false
3. *int*, returns the affected row count
`@TypeAdapter` may not be annotated on a `@SqlStatement` method. However it may be used on the method arguments.
#### Method Argument->Statement Parameter mapping
The parameter mapping rules are exactly the same as for `@SqlQuery`.
#### Example @SqlStatement usage
---JAVA---
public interface MyDao extends Dao {
// this statement does not return anything
@SqlStatement("update Product set productName = :name where productId = :id")
void setProductName(@Bind("id") long id, @Bind("name") String name);
// this statement returns true if at least one row was affected
@SqlStatement("update Product set productName = :name where productId = :id")
boolean renameProduct(@Bind("id") long id, @Bind("name") String name);
// this statement returns the number of affected rows
@SqlStatement("update Product set category = :new where category = :old")
int renameProductCategory(@Bind("old") String oldCategory, @Bind("new") String newCategory);
// You can update a field that requires a data type adapter
@SqlStatement("update Invoices set invoice = :2 where id = :1")
boolean setInvoice(long id, @TypeAdapter(InvoiceAdapterImpl.class) Invoice invoice);
}
---JAVA---
### Runtime Mode & External Statements
Sometimes you may need to specify a slightly different SQL statement for a database engine you might be using in development but not in production. For example, you might develop with H2 and deploy with PostgreSQL.
Being able to switch the DAO statements executed based on the runtime mode would be helpful for some scenarios. Iciql supports this use-case with a `DaoStatementProvider` and provides three mode options: `DEV`, `TEST`, and `PROD`.
#### External Statement DAO Example
---JAVA---
public interface MyDao extends Dao {
@SqlQuery("some.query")
Product [] getProductsWithRuntimeModeDependentQuery();
}
Db db = Db.open("jdbc:h2:mem:iciql");
// set a classpath statement resource provider
db.setDaoStatementProvider(new DaoClasspathStatementProvider());
// open the dao and retrieve the products
MyDao dao = db.open(MyDao.class);
Product [] products = dao.getProductsWithRuntimeModeDependentQuery();
---JAVA---
#### External Statement Resource Example
---FIXED---
some.query = select * from Products # default statement
%prod.some.query = select * from Products # will be used in PROD mode
%test.some.query = select * from Products where category = 'Beverages' # will be used in TEST mode
%dev.some.query = select * from Products where category = 'Condiments' # will be used in DEV mode
---FIXED---
#### DaoClasspathStatementProvider
Iciql ships with one useful implementation of a DaoStatementProvider: `DaoClasspathStatementProvider`.
This provider will load a single external statement resource from the classpath, if found. It tries to locate one of the following classpath resources and loads the first one identified using the `java.util.Properties` class.
1. `/iciql.properties`
2. `/iciql.xml`
3. `/conf/iciql.properties`
4. `/conf/iciql.xml`
Every `@SqlQuery` and `@SqlStatement` method will ask the `DaoStatementProvider` for the statement to execute based on the annotation value and the runtime mode. For the `DaoClasspathStatementProvider`, if the annotation value is not a key in the resource file it is assumed to be a statement and is returned to the DAO object for execution. This allows you to externalize a handful of statements - or all of them if you do not want to hard-code anything.

+ 0
- 145
src/site/dta.mkd View File

@@ -1,145 +0,0 @@
## Data Type Adapters
Data type adapters allow you to extend Iciql's support for field data types.
For example, you might want to take advantage of the [Postgres JSON/JSONB support](http://www.postgresql.org/docs/9.4/static/datatype-json.html) in 9.3/9.4 but instead of directly handling JSON text documents you might want to represent that JSON as a domain object and serialize/deserialize to JSON only when executing an SQL operation.
Data type adapters give you this flexibility.
**NOTE:** Data type adapters are reused within a Db instance and are not inherently thread-safe. You must handle thread-safety on your own, if it is an issue.
### An example
Consider the following model class.
---JAVA---
@IQTable
public class Invoices {
@IQColumn(primaryKey = true, autoIncrement = true)
public long _id;
@IQColumn
Date received;
@IQColumn
@TypeAdapter(InvoiceAdapterImpl.class)
Invoice invoice;
}
---JAVA---
This is a really simple table with three columns, but the third column uses a type adapter to map our *invoice* object field to an SQL type. You can use the `@TypeAdapter` annotation either on the field definition or on the class definition of your domain model.
Let's take a look at *InvoiceAdapterImpl*.
---JAVA---
public class InvoiceAdapterImpl implements DataTypeAdapter<Invoice> {
Mode mode;
@Override
public void setMode(Mode mode) {
this.mode = mode;
}
@Override
public String getDataType() {
return "jsonb";
}
@Override
public Class<Invoice> getJavaType() {
return Invoice.class;
}
Gson gson() {
return new GsonBuilder().create();
}
@Override
public Object serialize(Invoice value) {
String json = gson().toJson(value);
PGobject pg = new PGobject();
pg.setType(getDataType());
try {
pg.setValue(json);
} catch (SQLException e) {
// ignore, never thrown
}
return pg;
}
@Override
public Invoice deserialize(Object value) {
// the incoming object is always represented as a string
final String json = value.toString();
final Invoice invoice = gson().fromJson(json, getJavaType());
return invoice;
}
}
---JAVA---
Here you can see how the *InvoiceTypeAdapter* defines a [Postgres JSONB data type](http://www.postgresql.org/docs/9.4/static/datatype-json.html) and automatically handles JSON (de)serialization with [Google Gson](https://code.google.com/p/google-gson) so that the database gets the content in a form that it requires but we can continue to work with objects in Java.
### Runtime Mode
Data type adapters can respond to the Iciql runtime mode (`DEV`, `TEST`, or `PROD`) allowing them to change their behavior. This is useful for targetting a data type that might be available in your production database but may not be available in your development or testing database.
### Custom annotations
It is a little verbose to repeat `@TypeAdapter(InvoiceAdapterImpl.class)` everywhere you want to use your adapter.
To simplify this, you can implement your own annotation which specifies your type adapter.
---JAVA---
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
@TypeAdapter(InvoiceAdapterImpl.class)
public @interface InvoiceAdapter { }
---JAVA---
### Included Data Type Adapters
The following adapters are included in Iciql. They may require an optional dependency such as Gson, XStream, or SnakeYaml.
<table class="table">
<tr><td colspan="4"><b>Common Type Adapters</b></tr>
<tr><td><i>Adapter</i></td><td><i>Java</i></td><td><i>SQL</i></td><td><i>Description</i></td></tr>
<tr><td>com.iciql.adapter.JavaSerializationTypeAdapter</td><td>Object</td><td>BLOB</td><td>Uses Java serialization to (de)serialize your object</td></tr>
<tr><td>com.iciql.adapter.GsonTypeAdapter&lt;T&gt;</td><td>&lt;T&gt;</td><td>TEXT</td><td>
Uses Google Gson to (de)serialize your object as JSON</td></tr>
<tr><td>com.iciql.adapter.XStreamTypeAdapter</td><td>Object</td><td>TEXT</td><td>
Uses XStream to (de)serialize your object as XML</td></tr>
<tr><td>com.iciql.adapter.SnakeYamlTypeAdapter&lt;T&gt;</td><td>&lt;T&gt;</td><td>TEXT</td><td>
Uses SnakeYaml to (de)serialize your object as YAML</td></tr>
<tr><td colspan="4"><b>PostgreSQL Type Adapters</b></tr>
<tr><td><i>Object Adapters</i></td><td><i>Java</i></td><td><i>SQL</i></td><td><i>Description</i></td></tr>
<tr><td>com.iciql.adapter.postgresql.JsonObjectAdapter&lt;T&gt;</td><td>&lt;T&gt;</td><td>JSON</td><td>
Uses Google Gson to (de)serialize your object as JSON</td></tr>
<tr><td>com.iciql.adapter.postgresql.JsonbObjectAdapter&lt;T&gt;</td><td>&lt;T&gt;</td><td>JSONB</td><td>
Uses Google Gson to (de)serialize your object as JSONB</td></tr>
<tr><td>com.iciql.adapter.postgresql.XmlObjectAdapter</td><td>Object</td><td>XML</td><td>
Uses XStream to (de)serialize your object as XML</td></tr>
<tr><td colspan="4"><i>String Adapters</i></td></tr>
<tr><td>com.iciql.adapter.postgresql.JsonStringAdapter</td><td>String</td><td>JSON</td><td>
Maps the JSON data type to a java.lang.String</td></tr>
<tr><td>com.iciql.adapter.postgresql.JsonbStringAdapter</td><td>String</td><td>JSONB</td><td>
Maps the JSONB data type to a java.lang.String</td></tr>
<tr><td>com.iciql.adapter.postgresql.XmlStringAdapter</td><td>String</td><td>XML</td><td>
Maps the XML data type to a java.lang.String</td></tr>
</table>

+ 0
- 200
src/site/examples.mkd View File

@@ -1,200 +0,0 @@
## SQL DSL Examples
Here are some examples of using the Iciql SQL DSL.
### Select Statements
---JAVA---
// 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();
// select distinct customerId from customers where region='WA'
Customer c = new Customer();
List<String> customerIds = db.from(c).where(c.region).is("WA").selectDistinct(c.customerId);
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;
}});
---JAVA---
### Insert Statements
---JAVA---
// 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);
---JAVA---
### Update Statements
---JAVA---
// 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");
---JAVA---
### Upsert/Merge Statements
The Upsert or Merge methods will insert a new object if the primary key does not already exist or will update the record for the primary key.
---JAVA---
Product pChang = db.from(p).where(p.productName).is("Chang").selectFirst();
pChang.unitPrice = 19.5;
pChang.unitsInStock = 16;
db.merge(pChang);
---JAVA---
### Delete Statements
---JAVA---
// single record deletion
db.delete(singleProduct);
// batch record deletion
db.deleteAll(myProducts);
// delete query
db.from(p).where(p.productId).atLeast(10).delete();
---JAVA---
### Inner Join Statements
---JAVA---
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;
}});
---JAVA---
### View Statements
---JAVA---
// 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);
---JAVA---
### Dynamic Queries
Dynamic queries skip all field type checking and, depending on which approach you use, may skip model class/table name checking too.
---JAVA---
// 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);
---JAVA---

+ 0
- 136
src/site/index.mkd View File

@@ -1,136 +0,0 @@
## 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 (<250KB) 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] subproject
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]
### Fluent, type-safe SQL DSL with rich object mapping
Born from the unfinished [JaQu][jaqu] subproject of H2 in August 2011, Iciql has [advanced the codebase](jaqu_comparison.html) & DSL greatly. It supports more SQL syntax, more SQL data types, and all standard JDBC object types.
---JAVA---
try (Db db = Db.open("jdbc:h2:mem:iciql")) {
db.insertAll(Product.getList());
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");
}
---JAVA---
### Dynamic, annotated DAO with standard crud operations
Inspired by JDBI, Iciql offers a similar [DAO feature](dao.html). There are some clear benefits to using SQL directly rather than SQL-through-a-DSL so use each one where it makes the mose sense.
---JAVA---
// Define your DAO with SQL annotations and optional type adapters
public interface MyDao extends Dao {
@SqlQuery("select * from Product where unitsInStock = 0")
Product[] getProductsOutOfStock();
@SqlQuery("select * from Product where productId = :id")
Product getProduct(@Bind("id") long id);
// retrieve a custom type from the matched row in the Invoices table
@SqlQuery("select invoice from Invoices where id = :arg0")
@InvoiceAdapter
Invoice getInvoice(long id);
// retrieve a custom type from the matched row in the Invoices table
@SqlQuery("select invoice from Invoices where id = :p.invoiceId")
@InvoiceAdapter
Invoice getInvoice(@BindBean("p") Product product);
// update a custom type for the matched row in the Invoices table
@SqlStatement("update Invoices set invoice = :2 where id = :1")
boolean updateInvoice(long id, @InvoiceAdapter Invoice invoice);
}
// Define a type adapter annotation for the Invoice object
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER })
@TypeAdapter(InvoiceAdapterImpl.class)
public @interface InvoiceAdapter { }
// Create a DAO instance with your Db and work more clearly
try (Db db = Db.open("jdbc:h2:mem:iciql")) {
MyDao dao = db.open(MyDao.class);
dao.insertAll(Product.getList());
Product[] outofstock = dao.getProductsOutOfStock();
Product p = dao.getProduct(1);
Invoice i123 = dao.getInvoice(123);
i123.approved = true;
dao.updateInvoice(123, i123);
// use the underlying Db instance for full-power
dao.db().dropTable(Product.class);
}
---JAVA---
### Flexible field data types
The [Data Type Adapter feature](dta.html) allows you to customize how your SQL column data types map to/from Java objects.
This is very useful for mapping your field domain models to SQL without having to flatten them out to additional columns within your table. In other words, you can use your database as an object store at the column level by implementing a `@TypeAdapter` (de)serialization step.
You might use this to take advantage of the underlying database's type system. For example, PostgreSQL ships with the compelling JSON/JSONB/XML data types. Iciql provides String and Object adapters to facilitate use of those data types.
### Runtime mode support
Mode support allows you to tweak the behavior of your `@TypeAdapter` and `DAO` implementations to adapt to runtime conditions such as developing on a different database than you deploy on.
### 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}
- [SQLite](http://www.sqlite.org) ${sqlite.version}
Support for others is possible and may only require creating a simple "dialect" class.
### Downloading
As of 2.0.0 iciql is now distributed through Maven Central and it's coordinates have changed slightly.
---XML---
<dependencies>
<dependency>
<groupId>com.gitblit.iciql</groupId>
<artifactId>iciql</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
---XML---
### 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://www.querydsl.com/ "QueryDSL"
[hibernate]: http://www.hibernate.org "Hibernate"
[mybatis]: http://www.mybatis.org "mybatis"
[github]: http://github.com/gitblit/iciql "iciql git repository"
[apachelicense]: http://www.apache.org/licenses/LICENSE-2.0 "Apache License, Version 2.0"

+ 0
- 36
src/site/jaqu_comparison.mkd View File

@@ -1,36 +0,0 @@
## 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, PostreSQL, and SQLite</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>Foreign Key Constraints</td><td>model classes may be annotated with foreign key constraints</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><td>(NOT) IN</td><td>syntax (oneOf, noneOf) for specifying a (NOT) IN clause</td><td>--</td></tr>
<tr><td>compound nested conditions</td><td>WHERE (x = y OR x = z) AND (y = a OR y = b)</td><td>--</td></tr>
<tr><td>dynamic DAOs</td><td>DAO interfaces with annotated statements may be declared and dynamically generated</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>Custom</td><td>partially supported <em>uses custom-defined data type adapter (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>

+ 0
- 7
src/site/javadoc.mkd View File

@@ -1,7 +0,0 @@
<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>

+ 0
- 391
src/site/model_classes.mkd View File

@@ -1,391 +0,0 @@
## Table 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.
### Standard 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><i>variable</i><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>Custom</td> <td>create a DataTypeAdapter&lt;Custom&gt;</td>
<td>Custom</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.
---JAVA---
// notice the single ticks!
@IQColumn(defaultValue="'2000-01-01 00:00:00'")
Date myDate;
---JAVA---
2. setting a default value on the field<br/>
**NOTE:**<br/>
Primitive types have an implicit default value of *0* or *false*.
---JAVA---
@IQColumn
Date myDate = new Date(100, 0, 1);
@IQColumn
int myId;
---JAVA---
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
---JAVA---
@IQColumn(autoIncrement = true)
int myId;
---JAVA---
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
---JAVA---
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;
@IQColumn(typeAdapter = MyCustomClassAdapter.class)
private MyCustomClass;
// ignored because it is not annotated AND the class is @IQTable annotated
private Integer ignoredField;
public Product() {
// default constructor
}
}
---JAVA---
### Foreign Keys
---JAVA---
@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;
}
---JAVA---
### Views with Field Constraints
---JAVA---
@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 String toString() {
return productName + " (" + productId + ")";
}
}
---JAVA---
## 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.
---JAVA---
Date myDate;
public void defineIQ() {
// notice the single ticks!
Define.defaultValue(myDate, "'2000-01-01 00:00:00'");
}
---JAVA---
2. setting a default value on the field<br/>
**NOTE:**<br/>
Primitive types have an implicit default value of *0* or *false*.
---JAVA---
Date myDate = new Date(100, 0, 1);
int myId;
---JAVA---
### Example Interface Model
---JAVA---
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);
}
}
---JAVA---
## 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*.
---JAVA---
Date myDate = new Date(100, 0, 1);
int myId;
---JAVA---
### Example POJO Model
---JAVA---
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() {
}
}
---JAVA---

+ 0
- 28
src/site/performance.mkd View File

@@ -1,28 +0,0 @@
## 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.
SQLite uses the default [DELETE journaling mode](https://www.sqlite.org/lockingv3.html#rollback). About a 4x performance improvement can be achieved when using the [WAL journaling mode](https://www.sqlite.org/wal.html) (`PRAGMA journal_mode = WAL`).
External process databases (MySQL & PostgreSQL) use the default settings as provided by the platform.
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.
All bulk operations (insertAll, updateAll, deleteAll, etc) automatically create savepoints, if supported by the JDBC connector, to help ensure atomicity of the operation.
<pre>
%DBPERFORMANCE%
</pre>

+ 0
- 2
src/site/resources/.gitignore View File

@@ -1,2 +0,0 @@
/site_analytics.html
/site_ads.html

BIN
src/site/resources/iciql-favicon.png View File


BIN
src/site/resources/iciql.png View File


BIN
src/site/resources/iciql.xcf View File


BIN
src/site/resources/iciql2.png View File


BIN
src/site/resources/iciql2.xcf View File


BIN
src/site/resources/iciql_white.png View File


+ 0
- 52
src/site/resources/javadoc.css View File

@@ -1,52 +0,0 @@
/* 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 { }

+ 0
- 59
src/site/table_versioning.mkd View File

@@ -1,59 +0,0 @@
## 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=''.
### Effective use of Versioning with a DAO
When Iciql identifies that a version upgrade is necessary it will call the appropriate method and give you a `Db` instance. With the `Db` instance you may open a version-specific [DAO](dao.html) instance that could give you a clean way to define all your upgrade commands.
---JAVA---
public interface V2Upgrade extends Dao {
@SqlStatement("ALTER TABLE PRODUCT ADD COLUMN TEST INT DEFAULT 0")
void updateProductTable();
@SqlStatement("UPDATE PRODUCT SET CATEGORY = :new WHERE CATEGORY = :old"")
void renameCategory(@Bind("old") String oldName, @Bind("new") String newName);
}
public class MyUpgrader implements DbUpgrader {
public boolean upgradeDatabase(Db db, int fromVersion, int toVersion) {
if (2 == toVersion) {
V2Upgrade dao = db.open(V2Upgrade.class);
dao.updateProductTable();
dao.renameCategory("Condiments", "Dressings");
return true;
}
return false;
}
---JAVA---

+ 0
- 2
src/site/templates/atom.ftl View File

@@ -1,2 +0,0 @@
<#include "macros.ftl">
<@AtomMacro posts=releases posturl="${project.url}/history.html#" />

+ 0
- 147
src/site/templates/macros.ftl View File

@@ -1,147 +0,0 @@
<#macro LogMacro title version date description log logTitle="">
<#if log??>
<h3 id="${version}" class="section"><a href="#${version}" class="sectionlink"><i class="icon-share-alt"> </i></a>${title} (${version}) <small>${description}</small></h3>
<table class="table">
<tbody>
<tr>
<td style="background-color:inherit;width:100px">${date}</td>
<td style="background-color:inherit;"><@LogDescriptionMacro log=log title=logTitle /></td>
</tr>
</tbody>
</table>
</#if>
</#macro>
<#macro LogDescriptionMacro log title=log.title>
<#if (title!?length > 0)>
<p class="lead">${title}</p>
</#if>
<#if (log.html!?length > 0)>
<p>${log.html}</p>
</#if>
<#if (log.text!?length > 0)>
<blockquote><p>${log.text!?html?replace("\n", "<br />")}</p></blockquote>
</#if>
<#if (log.note!?length > 0)>
<div class="alert alert-info">
<h4>Note</h4>
${log.note?html?replace("\n", "<p />")}
</div>
</#if>
<#if (log.security!?size > 0)>
<@SecurityListMacro title="security" list=log.security/>
</#if>
<#if (log.fixes!?size > 0)>
<@UnorderedListMacro title="fixes" list=log.fixes />
</#if>
<#if (log.changes!?size > 0)>
<@UnorderedListMacro title="changes" list=log.changes />
</#if>
<#if (log.additions!?size > 0)>
<@UnorderedListMacro title="additions" list=log.additions />
</#if>
<#if (log.settings!?size > 0)>
<@SettingsTableMacro title="new settings" list=log.settings />
</#if>
<#if (log.dependencyChanges!?size > 0)>
<@UnorderedListMacro title="dependency changes" list=log.dependencyChanges />
</#if>
<#if (log.contributors!?size > 0)>
<@UnorderedListMacro title="contributors" list=log.contributors?sort />
</#if>
</#macro>
<#macro SecurityListMacro list title>
<h4 style="color:red;">${title}</h4>
<ul>
<#list list as item>
<li>${item?html?replace("\n", "<br/>")}</li>
</#list>
</ul>
</#macro>
<#macro UnorderedListMacro list title>
<h4>${title}</h4>
<ul>
<#list list as item>
<li>${item?html?replace("\n", "<br/>")}</li>
</#list>
</ul>
</#macro>
<#macro SettingsTableMacro list title>
<h4>${title}</h4>
<table class="table">
<#list list as item>
<tr>
<td><em>${item.name}</em></td><td>${item.defaultValue}</td>
</tr>
</#list>
</table>
</#macro>
<#macro RssMacro posts posturl>
<?xml version="1.0" standalone='yes'?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
<title><![CDATA[${project.name}]]></title>
<link>${project.url}</link>
<description><![CDATA[${project.description}]]></description>
<generator>Moxie Toolkit</generator>
<#list posts as post>
<item>
<title><![CDATA[${post.title}]]></title>
<link><![CDATA[${posturl}${post.id}]]></link>
<guid isPermaLink="true">${posturl}${post.id}</guid>
<#if (post.text!?length > 0)>
<description><![CDATA[${post.text}]]></description>
</#if>
<#if (post.keywords!?size > 0)>
<#list post.keywords as keyword>
<category><![CDATA[${keyword}]]></category>
</#list>
</#if>
<#if (post.author!?length > 0)>
<dc:creator><![CDATA[${post.author}]]></dc:creator>
<#else>
<dc:creator><![CDATA[${project.name}]]></dc:creator>
</#if>
<pubDate>${post.date?string("EEE, dd MMM yyyy HH:mm:ss Z")}</pubDate>
</item>
</#list>
</channel>
</rss>
</#macro>
<#macro AtomMacro posts posturl>
<?xml version="1.0" standalone='yes'?>
<feed xmlns="http://www.w3.org/2005/Atom">
<generator uri="${project.url}" version="${project.version}">${project.name}</generator>
<title><![CDATA[${project.name}]]></title>
<updated>${project.releaseDate}</updated>
<#list posts as post>
<entry>
<content type="text/plain" />
<title type="text"><![CDATA[${post.title}]]></title>
<#if (post.text!?length > 0)>
<summary type="text"><![CDATA[${post.text}]]></summary>
</#if>
<link href="${posturl}${post.id}" rel="via" />
<guid isPermaLink="true">${posturl}${post.id}</guid>
<#if (post.text!?length > 0)>
<content><![CDATA[${post.text}]]></content>
</#if>
<#if (post.keywords!?size > 0)>
<#list post.keywords as keyword>
<category label="<![CDATA[${keyword}]]>" />
</#list>
</#if>
<published>${post.date?string("yyyy-MM-dd'T'HH:mm:ssZ")}</published>
</entry>
</#list>
</feed>
</#macro>

+ 0
- 25
src/site/templates/releasecurrent.ftl View File

@@ -1,25 +0,0 @@
<#include "macros.ftl" >

<!-- CURRENT RELEASE -->
<@LogMacro
title="Current Release"
log=release
version=project.releaseVersion
date=reference.releaseDate?string("yyyy-MM-dd")
description="this is the current stable release" />

<!-- NEXT RELEASE -->
<#if snapshot??>
<@LogMacro
title="Next Release"
log=snapshot
version=project.version
date="PENDING"
description="these changes are queued for an upcoming release" />
</#if>

<div>
<ul class="pager">
<li class="next"><a href="releases.html">All Releases &rarr;</a></li>
</ul>
</div>

+ 0
- 21
src/site/templates/releasehistory.ftl View File

@@ -1,21 +0,0 @@
<#include "macros.ftl" >

<!-- HISTORY -->
<#if (releases!?size > 0)>
<p></p>
<h2>All Releases</h2>
<table class="table">
<tbody>
<!-- RELEASE HISTORY -->
<#list releases?sort_by("date")?reverse as log>
<tr id="${log.id}">
<td style="width:100px" id="${log.id}">
<b><a href="#${log.id}">${log.id}</a></b><br/>
${log.date?string("yyyy-MM-dd")}
</td>
<td><@LogDescriptionMacro log=log /></td>
</tr>
</#list>
</tbody>
</table>
</#if>

+ 0
- 2
src/site/templates/rss.ftl View File

@@ -1,2 +0,0 @@
<#include "macros.ftl">
<@RssMacro posts=releases posturl="${project.url}/releases.html#" />

+ 0
- 98
src/site/tools.mkd View File

@@ -1,98 +0,0 @@
## 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.
---FIXED---
win: java -cp iciql.jar;your_db_driver.jar <parameters>
*nix: java -cp iciql.jar:your_db_driver.jar <parameters>
---FIXED---
### 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 &nbsp; </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:
---JAVA---
public static enum Level {
CONSIDER, WARN, ERROR;
}
---JAVA---
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
---JAVA---
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);
}
}
---JAVA---

+ 0
- 272
src/site/usage.mkd View File

@@ -1,272 +0,0 @@
## SQL DSL Usage
Aside from this brief usage guide, please consult the [DSL 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:
---JAVA---
Db.open(String url, String user, String password);
Db.open(String url, String user, char[] password);
Db.open(Connection conn);
Db.open(DataSource dataSource);
---JAVA---
### 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.
---JAVA---
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();
---JAVA---
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.
---JAVA---
List<Product> restock = db.from(p).where("unitsInStock=? and productName like ? order by productId", 0, "Chef%").select();
---JAVA---
#### 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.
---JAVA---
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);
---JAVA---
Or if you want access to the raw *ResultSet* before building your model object instances...
---JAVA---
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);
---JAVA---
### Compound Nested Conditions
It is possible to specify type-safe compound nested conditions in your WHERE clauses using `And` and `Or` statements.
---JAVA---
final Customer model = new Customer();
// SELECT * FROM CUSTOMERS
// WHERE customerId IS NOT NULL
// AND region IS NOT NULL
// AND (
// region = 'LA' OR region = 'CA'
// )
List<Customer> regionals = db.from(model)
.where(model.customerId).isNotNull()
.and(model.region).isNotNull()
.and(new Or<Customer>(db, model) {{
or(model.region).is("LA");
or(model.region).is("CA");
}});
---JAVA---
### Finding Matches for a List of Values
You can use SQL's *IN* WHERE clause with the `oneOf` or `noneOf` conditions.
---JAVA---
final Customer model = new Customer();
List<Customer> regionals = db.from(model).where(model.region).oneOf("CA", "LA");
List<Customer> others = db.from(model).where(model.region).noneOf("CA", "LA");
---JAVA---
### Read-only Views
View model classes can inherit their field definitions from a parent table model class.
---JAVA---
@IQView(name = "AnnotatedProductViewInherited", inheritColumns = true)
public class ProductViewFromQuery extends ProductAnnotationOnly {
public String unmappedField;
@IQColumn(name = "id")
public Long productId;
public String toString() {
return productName + " (" + productId + ")";
}
}
---JAVA---
You can then create or replace the VIEW in the database using a fluent syntax.
---JAVA---
// 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();
// 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();
---JAVA---
### Natural Syntax
<span class="alert alert-warning">Not Actively Developed</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:
---JAVA---
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();
---JAVA---
### 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
---JAVA---
IciqlLogger.activeConsoleLogger();
IciqlLogger.deactiveConsoleLogger();
---JAVA---
#### SLF4J Logging
---JAVA---
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);
---JAVA---
#### Custom Logging
---JAVA---
IciqlListener custom = new IciqlListener() {
public void logIciql(StatementType type, String statement) {
// do log
}
};
IciqlLogger.registerListener(custom);
IciqlLogger.unregisterListener(custom);
---JAVA---
## Understanding Aliases and Model Classes
Consider the following example:
---JAVA---
Product p = new Product();
List<Product> restock = db.from(p).where(p.unitsInStock).is(0).select();
---JAVA---
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.
---JAVA---
final ThreadLocal<Product> p = Utils.newThreadLocal(Product.class);
db.from(p.get()).select();
---JAVA---
## 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>
---JAVA---
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();
}
---JAVA---
</td><td>
---JAVA---
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();
}
---JAVA---
</td></tr>
</table>

Loading…
Cancel
Save