jaqu.html 11.6 KB
Newer Older
1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2
<!--
3
Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, Version 1.0,
4
and under the Eclipse Public License, Version 1.0
5
(http://h2database.com/html/license.html).
6 7 8 9 10 11
Initial Developer: H2 Group
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
JaQu
</title><link rel="stylesheet" type="text/css" href="stylesheet.css" />
12
<!-- [search] { -->
13 14 15
<script type="text/javascript" src="navigation.js"></script>
</head><body onload="frameMe();">
<table class="content"><tr class="content"><td class="content"><div class="contentDiv">
16
<!-- } -->
17 18

<h1>JaQu</h1>
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
<a href="#what_is_jaqu">
    What is JaQu</a><br />
<a href="#differences">
    Differences to Other Data Access Tools</a><br />
<a href="#current_state">
    Current State</a><br />
<a href="#building_jaqu">
    Building the JaQu Library</a><br />
<a href="#requirements">
    Requirements</a><br />
<a href="#example_code">
    Example Code</a><br />
<a href="#configuration">
    Configuration</a><br />
<a href="#natural_syntax">
    Natural Syntax</a><br />
<a href="#other_ideas">
    Other Ideas</a><br />
<a href="#similar_projects">
    Similar Projects</a><br />

<h2 id="what_is_jaqu">What is JaQu</h2>
41
<p>
Thomas Mueller's avatar
Thomas Mueller committed
42
Note: This project is currently in maintenance mode.
Thomas Mueller's avatar
Thomas Mueller committed
43
A friendly fork of JaQu is
Thomas Mueller's avatar
Thomas Mueller committed
44 45 46
<a href="http://iciql.com">available under the name iciql</a>.
</p>
<p>
47
JaQu stands for Java Query and allows to access databases using pure Java.
Thomas Mueller's avatar
Thomas Mueller committed
48
JaQu provides a fluent interface (or internal DSL).
49
JaQu is something like LINQ for Java (LINQ stands for "language integrated query" and is a
50 51
Microsoft .NET technology). The following JaQu code:
</p>
52
<pre>
53
Product p = new Product();
54
List&lt;Product&gt; soldOutProducts =
Thomas Mueller's avatar
Thomas Mueller committed
55
    db.from(p).where(p.unitsInStock).is(0).select();
56 57 58 59
</pre>
<p>
stands for the SQL statement:
</p>
60
<pre>
61
SELECT * FROM PRODUCTS P
62 63 64
WHERE P.UNITS_IN_STOCK = 0
</pre>

65
<h2 id="differences">Differences to Other Data Access Tools</h2>
66
<p>
67
Unlike SQL, JaQu can be easily integrated in Java applications. Because JaQu is pure Java,
Thomas Mueller's avatar
Thomas Mueller committed
68
auto-complete in the IDE is supported. Type checking is performed by the compiler.
69
JaQu fully protects against SQL injection.
Thomas Mueller's avatar
Thomas Mueller committed
70 71
</p>
<p>
Thomas Mueller's avatar
Thomas Mueller committed
72 73
JaQu is meant as replacement for JDBC and SQL and not as much as a replacement for tools like Hibernate.
With JaQu, you don't write SQL statements as strings.
Thomas Mueller's avatar
Thomas Mueller committed
74 75
JaQu is much smaller and simpler than other persistence frameworks such as Hibernate,
but it also does not provide all the features of those.
76
Unlike iBatis and Hibernate, no XML or annotation based configuration is required;
Thomas Mueller's avatar
Thomas Mueller committed
77
instead the configuration (if required at all) is done in pure Java, within the application.
Thomas Mueller's avatar
Thomas Mueller committed
78 79
</p>
<p>
80
JaQu does not require or contain any data caching mechanism. Like JDBC and iBatis,
Thomas Mueller's avatar
Thomas Mueller committed
81
JaQu provides full control over when and what SQL statements are executed
Thomas Mueller's avatar
Thomas Mueller committed
82
(but without having to write SQL statements as strings).
83 84
</p>

85 86
<h3>Restrictions</h3>
<p>
87 88
Primitive types (eg. <code>boolean, int, long, double</code>) are not supported.
Use <code>java.lang.Boolean, Integer, Long, Double</code> instead.
89 90
</p>

91 92
<h3>Why in Java?</h3>
<p>
Thomas Mueller's avatar
Thomas Mueller committed
93 94 95
Most applications are written in Java. Mixing Java and another language (for example Scala or Groovy)
in the same application is complicated: you would need to split the application and database code,
and write adapter / wrapper code.
96 97
</p>

98
<h2 id="current_state">Current State</h2>
99
<p>
100 101
Currently, JaQu is only tested with the H2 database. The API may change in future versions.
JaQu is not part of the h2 jar file, however the source code is included in H2, under:
102
</p>
103 104
<ul><li><code>src/test/org/h2/test/jaqu/*</code> (samples and tests)
</li><li><code>src/tools/org/h2/jaqu/*</code> (framework)
105 106
</li></ul>

107
<h2 id="building_jaqu">Building the JaQu Library</h2>
108
<p>
109
To create the JaQu jar file, run: <code>build jarJaqu</code>. This will create the file <code>bin/h2jaqu.jar</code>.
110 111
</p>

112
<h2 id="requirements">Requirements</h2>
113 114
<p>
JaQu requires Java 1.5. Annotations are not need.
115
Currently, JaQu is only tested with the H2 database engine, however in theory it should
116 117 118
work with any database that supports the JDBC API.
</p>

119
<h2 id="example_code">Example Code</h2>
120
<pre>
121 122 123 124 125 126 127
package org.h2.test.jaqu;
import java.math.BigDecimal;
import java.util.List;
import org.h2.jaqu.Db;
import static org.h2.jaqu.Function.*;

public class Test {
Thomas Mueller's avatar
Thomas Mueller committed
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
    Db db;

    public static void main(String[] args) throws Exception {
        new SamplesTest().test();
    }

    public void test() throws Exception {
        db = Db.open("jdbc:h2:mem:", "sa", "sa");
        db.insertAll(Product.getProductList());
        db.insertAll(Customer.getCustomerList());
        db.insertAll(Order.getOrderList());
        testLength();
        testCount();
        testGroup();
        testSelectManyCompoundFrom2();
        testWhereSimple4();
        testSelectSimple2();
        testAnonymousTypes3();
        testWhereSimple2();
        testWhereSimple3();
        db.close();
    }

    private void testWhereSimple2() throws Exception {
        Product p = new Product();
153
        List&lt;Product&gt; soldOutProducts =
Thomas Mueller's avatar
Thomas Mueller committed
154 155 156 157 158 159 160
            db.from(p).
            where(p.unitsInStock).is(0).
            orderBy(p.productId).select();
    }

    private void testWhereSimple3() throws Exception {
        Product p = new Product();
161
        List&lt;Product&gt; expensiveInStockProducts =
Thomas Mueller's avatar
Thomas Mueller committed
162 163 164 165 166 167 168 169
            db.from(p).
            where(p.unitsInStock).bigger(0).
            and(p.unitPrice).bigger(3.0).
            orderBy(p.productId).select();
    }

    private void testWhereSimple4() throws Exception {
        Customer c = new Customer();
170
        List&lt;Customer&gt; waCustomers =
Thomas Mueller's avatar
Thomas Mueller committed
171 172 173 174 175 176 177
            db.from(c).
            where(c.region).is("WA").
            select();
    }

    private void testSelectSimple2() throws Exception {
        Product p = new Product();
178
        List&lt;String&gt; productNames =
Thomas Mueller's avatar
Thomas Mueller committed
179 180 181 182 183 184 185 186 187 188 189 190
            db.from(p).
            orderBy(p.productId).select(p.productName);
    }

    public static class ProductPrice {
        public String productName;
        public String category;
        public Double price;
    }

    private void testAnonymousTypes3() throws Exception {
        final Product p = new Product();
191
        List&lt;ProductPrice&gt; productInfos =
Thomas Mueller's avatar
Thomas Mueller committed
192
            db.from(p).orderBy(p.productId).
Thomas Mueller's avatar
Thomas Mueller committed
193
            select(new ProductPrice() {{
Thomas Mueller's avatar
Thomas Mueller committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
                    productName = p.productName;
                    category = p.category;
                    price = p.unitPrice;
            }});
    }

    public static class CustOrder {
        public String customerId;
        public Integer orderId;
        public BigDecimal total;
    }

    private void testSelectManyCompoundFrom2() throws Exception {
        final Customer c = new Customer();
        final Order o = new Order();
209
        List&lt;CustOrder&gt; orders =
Thomas Mueller's avatar
Thomas Mueller committed
210 211 212 213
            db.from(c).
            innerJoin(o).on(c.customerId).is(o.customerId).
            where(o.total).smaller(new BigDecimal("500.00")).
            orderBy(1).
Thomas Mueller's avatar
Thomas Mueller committed
214
            select(new CustOrder() {{
Thomas Mueller's avatar
Thomas Mueller committed
215 216 217 218 219 220 221 222
                customerId = c.customerId;
                orderId = o.orderId;
                total = o.total;
            }});
    }

    private void testLength() throws Exception {
        Product p = new Product();
223
        List&lt;Integer&gt; lengths =
Thomas Mueller's avatar
Thomas Mueller committed
224
            db.from(p).
Thomas Mueller's avatar
Thomas Mueller committed
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
            where(length(p.productName)).smaller(10).
            orderBy(1).
            selectDistinct(length(p.productName));
    }

    private void testCount() throws Exception {
        long count = db.from(new Product()).selectCount();
    }

    public static class ProductGroup {
        public String category;
        public Long productCount;
    }

    private void testGroup() throws Exception {
        final Product p = new Product();
241
        List&lt;ProductGroup&gt; list =
Thomas Mueller's avatar
Thomas Mueller committed
242 243 244
            db.from(p).
            groupBy(p.category).
            orderBy(1).
Thomas Mueller's avatar
Thomas Mueller committed
245
            select(new ProductGroup() {{
Thomas Mueller's avatar
Thomas Mueller committed
246 247 248 249
                category = p.category;
                productCount = count();
            }});
    }
250 251 252 253

}
</pre>

254
<h2 id="configuration">Configuration</h2>
255
<p>
Thomas Mueller's avatar
Thomas Mueller committed
256
JaQu does not require any configuration when using the default field to column mapping.
257
To define table indices, or if you want to map a class to a table with a different name,
258
or a field to a column with another name, create a function called <code>define</code> in the data class.
259 260
Example:
</p>
261
<pre>
Thomas Mueller's avatar
Thomas Mueller committed
262 263
import static org.h2.jaqu.Define.*;

264 265 266 267 268 269 270
public class Product implements Table {

    public Integer productId;
    public String productName;
    public String category;
    public Double unitPrice;
    public Integer unitsInStock;
271

272 273 274 275 276
    public void define() {
        tableName("Product");
        primaryKey(productId);
        index(productName, category);
    }
Thomas Mueller's avatar
Thomas Mueller committed
277 278

}
279 280
</pre>
<p>
281
The method <code>define()</code> contains the mapping definition. It is called once
282 283 284
when the class is used for the first time. Like annotations, the mapping is defined in the class itself.
Unlike when using annotations, the compiler can check the syntax even for multi-column
objects (multi-column indexes, multi-column primary keys and so on).
Thomas Mueller's avatar
Thomas Mueller committed
285 286
Because the definition is written in Java, the configuration can be set at runtime,
which is not possible using annotations.
Thomas Mueller's avatar
Thomas Mueller committed
287
Unlike XML mapping configuration, the configuration is integrated in the class itself.
288 289
</p>

290
<h2 id="natural_syntax">Natural Syntax</h2>
291 292
<p>The plan is to support more natural (pure Java) syntax in conditions.
To do that, the condition class is de-compiled to a SQL condition.
Thomas Mueller's avatar
Thomas Mueller committed
293
A proof of concept decompiler is included (but it doesn't fully work yet; patches are welcome).
294 295
The planned syntax is:
</p>
296
<pre>
297 298 299 300 301 302 303 304 305 306 307 308
long count = db.from(co).
    where(new Filter() { public boolean where() {
        return co.id == x
            &amp;&amp; co.name.equals(name)
            &amp;&amp; co.value == new BigDecimal("1")
            &amp;&amp; co.amount == 1L
            &amp;&amp; co.birthday.before(new java.util.Date())
            &amp;&amp; co.created.before(java.sql.Timestamp.valueOf("2005-05-05 05:05:05"))
            &amp;&amp; co.time.before(java.sql.Time.valueOf("23:23:23"));
        } }).selectCount();
</pre>

309
<h2 id="other_ideas">Other Ideas</h2>
310 311
<p>
This project has just been started, and nothing is fixed yet.
Thomas Mueller's avatar
Thomas Mueller committed
312
Some ideas are:
313
</p>
314 315
<ul><li>Support queries on collections (instead of using a database).
</li><li>Provide API level compatibility with JPA (so that JaQu can be used as an extension of JPA).
316 317 318 319
</li><li>Internally use a JPA implementation (for example Hibernate) instead of SQL directly.
</li><li>Use PreparedStatements and cache them.
</li></ul>

320
<h2 id="similar_projects">Similar Projects</h2>
321
<p class="notranslate">
Thomas Mueller's avatar
Thomas Mueller committed
322
<a href="http://iciql.com">iciql (a friendly fork of JaQu)</a><br />
323
<a href="http://www.cementframework.org">Cement Framework</a><br />
324
<a href="http://code.google.com/p/dreamsource-orm">Dreamsource ORM</a><br />
325 326
<a href="http://incubator.apache.org/empire-db/empiredb/empiredb.htm">Empire-db</a><br />
<a href="http://www.jequel.de">JEQUEL: Java Embedded QUEry Language</a><br />
327
<a href="http://joist.ws">Joist</a><br />
Thomas Mueller's avatar
Thomas Mueller committed
328
<a href="http://www.jooq.org">jOOQ</a><br />
329 330
<a href="http://josql.sourceforge.net">JoSQL</a><br />
<a href="http://code.google.com/p/liquidform">LIQUidFORM</a><br />
331
<a href="http://svn.quaere.codehaus.org/browse/~raw,r=76/quaere/trunk/Quaere/src/test/java/org/quaere/alias/test/SamplesTest.java">Quaere (Alias implementation)</a><br />
332 333
<a href="http://quaere.codehaus.org/">Quaere</a><br />
<a href="http://source.mysema.com/display/querydsl/Querydsl">Querydsl</a><br />
334
<a href="http://squill.dev.java.net">Squill</a><br />
335 336
</p>

337 338
<!-- [close] { --></div></td></tr></table><!-- } --><!-- analytics --></body></html>