jaqu.html 11.1 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
<!--
Thomas Mueller's avatar
Thomas Mueller committed
3
Copyright 2004-2009 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>
42
JaQu stands for Java Query and allows to access databases using pure Java.
43
JaQu provides a fluent interface (or internal DSL) for building SQL statements.
Thomas Mueller's avatar
Thomas Mueller committed
44
JaQu replaces SQL, JDBC, and persistence frameworks such as Hibernate.
45
JaQu is something like LINQ for Java (LINQ stands for "language integrated query" and is a
46 47
Microsoft .NET technology). The following JaQu code:
</p>
48
<pre>
49
Product p = new Product();
50
List&lt;Product&gt; soldOutProducts =
Thomas Mueller's avatar
Thomas Mueller committed
51
    db.from(p).where(p.unitsInStock).is(0).select();
52 53 54 55
</pre>
<p>
stands for the SQL statement:
</p>
56
<pre>
57
SELECT * FROM PRODUCTS P
58 59 60
WHERE P.UNITS_IN_STOCK = 0
</pre>

61
<h2 id="differences">Differences to Other Data Access Tools</h2>
62
<p>
63
Unlike SQL, JaQu can be easily integrated in Java applications. Because JaQu is pure Java,
Thomas Mueller's avatar
Thomas Mueller committed
64
auto-complete in the IDE and Javadoc and are supported. Type checking is performed by the compiler.
65
JaQu fully protects against SQL injection.
Thomas Mueller's avatar
Thomas Mueller committed
66 67
</p>
<p>
Thomas Mueller's avatar
Thomas Mueller committed
68
JaQu is much smaller than persistence frameworks such as Hibernate.
69
Unlike iBatis and Hibernate, no XML or annotation based configuration is required;
Thomas Mueller's avatar
Thomas Mueller committed
70 71 72
instead the configuration (if required at all) is done in pure Java, in the application itself.
</p>
<p>
73
JaQu does not require or contain any data caching mechanism. Like JDBC and iBatis,
Thomas Mueller's avatar
Thomas Mueller committed
74
JaQu provides full control over when and what SQL statements are executed.
75 76
</p>

77 78
<h3>Restrictions</h3>
<p>
79 80
Primitive types (eg. <code>boolean, int, long, double</code>) are not supported.
Use <code>java.lang.Boolean, Integer, Long, Double</code> instead.
81 82
</p>

83 84 85
<h3>Why in Java?</h3>
<p>
Most people use Java in their application. Mixing Java and another language (for example Scala or Groovy)
Thomas Mueller's avatar
Thomas Mueller committed
86
in the same application is complicated: you would need to split the application and database code.
87 88
</p>

89
<h2 id="current_state">Current State</h2>
90
<p>
91 92
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:
93
</p>
94 95
<ul><li><code>src/test/org/h2/test/jaqu/*</code> (samples and tests)
</li><li><code>src/tools/org/h2/jaqu/*</code> (framework)
96 97
</li></ul>

98
<h2 id="building_jaqu">Building the JaQu Library</h2>
99
<p>
100
To create the JaQu jar file, run: <code>build jarJaqu</code>. This will create the file <code>bin/h2jaqu.jar</code>.
101 102
</p>

103
<h2 id="requirements">Requirements</h2>
104 105
<p>
JaQu requires Java 1.5. Annotations are not need.
106
Currently, JaQu is only tested with the H2 database engine, however in theory it should
107 108 109
work with any database that supports the JDBC API.
</p>

110
<h2 id="example_code">Example Code</h2>
111
<pre>
112 113 114 115 116 117 118
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
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
    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();
144
        List&lt;Product&gt; soldOutProducts =
Thomas Mueller's avatar
Thomas Mueller committed
145 146 147 148 149 150 151
            db.from(p).
            where(p.unitsInStock).is(0).
            orderBy(p.productId).select();
    }

    private void testWhereSimple3() throws Exception {
        Product p = new Product();
152
        List&lt;Product&gt; expensiveInStockProducts =
Thomas Mueller's avatar
Thomas Mueller committed
153 154 155 156 157 158 159 160
            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();
161
        List&lt;Customer&gt; waCustomers =
Thomas Mueller's avatar
Thomas Mueller committed
162 163 164 165 166 167 168
            db.from(c).
            where(c.region).is("WA").
            select();
    }

    private void testSelectSimple2() throws Exception {
        Product p = new Product();
169
        List&lt;String&gt; productNames =
Thomas Mueller's avatar
Thomas Mueller committed
170 171 172 173 174 175 176 177 178 179 180 181
            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();
182
        List&lt;ProductPrice&gt; productInfos =
Thomas Mueller's avatar
Thomas Mueller committed
183
            db.from(p).orderBy(p.productId).
Thomas Mueller's avatar
Thomas Mueller committed
184
            select(new ProductPrice() {{
Thomas Mueller's avatar
Thomas Mueller committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
                    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();
200
        List&lt;CustOrder&gt; orders =
Thomas Mueller's avatar
Thomas Mueller committed
201 202 203 204
            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
205
            select(new CustOrder() {{
Thomas Mueller's avatar
Thomas Mueller committed
206 207 208 209 210 211 212 213
                customerId = c.customerId;
                orderId = o.orderId;
                total = o.total;
            }});
    }

    private void testLength() throws Exception {
        Product p = new Product();
214
        List&lt;Integer&gt; lengths =
Thomas Mueller's avatar
Thomas Mueller committed
215
            db.from(p).
Thomas Mueller's avatar
Thomas Mueller committed
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
            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();
232
        List&lt;ProductGroup&gt; list =
Thomas Mueller's avatar
Thomas Mueller committed
233 234 235
            db.from(p).
            groupBy(p.category).
            orderBy(1).
Thomas Mueller's avatar
Thomas Mueller committed
236
            select(new ProductGroup() {{
Thomas Mueller's avatar
Thomas Mueller committed
237 238 239 240
                category = p.category;
                productCount = count();
            }});
    }
241 242 243 244

}
</pre>

245
<h2 id="configuration">Configuration</h2>
246
<p>
Thomas Mueller's avatar
Thomas Mueller committed
247
JaQu does not require any configuration when using the default mapping.
248
To define table indices, or if you want to map a class to a table with a different name,
249
or a field to a column with another name, create a function called <code>define</code> in the data class.
250 251
Example:
</p>
252
<pre>
253 254 255 256 257 258 259
public class Product implements Table {

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

261 262 263 264 265
    public void define() {
        tableName("Product");
        primaryKey(productId);
        index(productName, category);
    }
Thomas Mueller's avatar
Thomas Mueller committed
266 267

}
268 269
</pre>
<p>
270
The method <code>define()</code> contains the mapping definition. It is called once
271 272 273
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
274 275 276
Because the definition is written in regular Java, the configuration can depend on the environment.
This is not possible using annotations.
Unlike XML mapping configuration, the configuration is integrated in the class itself.
277 278
</p>

279
<h2 id="natural_syntax">Natural Syntax</h2>
280 281 282 283 284
<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.
A proof of concept decompiler is included (but it doesn't work yet).
The planned syntax is:
</p>
285
<pre>
286 287 288 289 290 291 292 293 294 295 296 297
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>

298
<h2 id="other_ideas">Other Ideas</h2>
299 300
<p>
This project has just been started, and nothing is fixed yet.
Thomas Mueller's avatar
Thomas Mueller committed
301
Some ideas for what to implement are:
302
</p>
303 304
<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).
305 306 307 308
</li><li>Internally use a JPA implementation (for example Hibernate) instead of SQL directly.
</li><li>Use PreparedStatements and cache them.
</li></ul>

309
<h2 id="similar_projects">Similar Projects</h2>
310
<p class="notranslate">
311
<a href="http://www.cementframework.org">Cement Framework</a><br />
312
<a href="http://code.google.com/p/dreamsource-orm">Dreamsource ORM</a><br />
313 314
<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 />
315
<a href="http://joist.ws">Joist</a><br />
316 317
<a href="http://josql.sourceforge.net">JoSQL</a><br />
<a href="http://code.google.com/p/liquidform">LIQUidFORM</a><br />
318
<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 />
319 320
<a href="http://quaere.codehaus.org/">Quaere</a><br />
<a href="http://source.mysema.com/display/querydsl/Querydsl">Querydsl</a><br />
321
<a href="http://squill.dev.java.net">Squill</a><br />
322 323
</p>

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