提交 902de3ff authored 作者: Thomas Mueller's avatar Thomas Mueller

JaQu improvements

上级 faab0abd
...@@ -130,9 +130,15 @@ public class Product implements Table { ...@@ -130,9 +130,15 @@ public class Product implements Table {
create(74, "Longlife Tofu", "Produce", 10.0, 4), create(74, "Longlife Tofu", "Produce", 10.0, 4),
create(75, "Rhoenbraeu Klosterbier", "Beverages", 7.7500, 125), create(75, "Rhoenbraeu Klosterbier", "Beverages", 7.7500, 125),
create(76, "Lakkalikoeoeri", "Beverages", 18.0, 57), create(76, "Lakkalikoeoeri", "Beverages", 18.0, 57),
create(77, "Original Frankfurter gruene Sosse", "Condiments", 13.0, 32) }; create(77, "Original Frankfurter gruene Sosse", "Condiments", 13.0, 32),
};
return Arrays.asList(list); return Arrays.asList(list);
} }
public String toString() {
return productName + ": " + unitsInStock;
}
} }
//## Java 1.5 end ## //## Java 1.5 end ##
...@@ -43,6 +43,15 @@ public class SamplesTest extends TestBase { ...@@ -43,6 +43,15 @@ public class SamplesTest extends TestBase {
db.insertAll(Product.getProductList()); db.insertAll(Product.getProductList());
db.insertAll(Customer.getCustomerList()); db.insertAll(Customer.getCustomerList());
db.insertAll(Order.getOrderList()); db.insertAll(Order.getOrderList());
// TODO SUM, MIN, MAX, LIKE, LIKE ESCAPE...
// TODO +, -, *, /, ||, nested operations
// TODO nested AND/OR
// TODO NOT
// TODO DELETE: FROM ... DELETE?
// TODO UPDATE: FROM ... UPDATE?
// TODO SELECT UNION
testLength();
testCount();
testGroup(); testGroup();
testSelectManyCompoundFrom2(); testSelectManyCompoundFrom2();
testWhereSimple4(); testWhereSimple4();
...@@ -50,7 +59,6 @@ public class SamplesTest extends TestBase { ...@@ -50,7 +59,6 @@ public class SamplesTest extends TestBase {
testAnonymousTypes3(); testAnonymousTypes3();
testWhereSimple2(); testWhereSimple2();
testWhereSimple3(); testWhereSimple3();
testCountStar();
db.close(); db.close();
//## Java 1.5 end ## //## Java 1.5 end ##
} }
...@@ -252,19 +260,28 @@ public class SamplesTest extends TestBase { ...@@ -252,19 +260,28 @@ public class SamplesTest extends TestBase {
"c:ANTON/o:10365;c:ANTON/o:10682;", s); "c:ANTON/o:10365;c:ANTON/o:10682;", s);
} }
private void testCountStar() throws Exception { private void testLength() throws Exception {
long count = db.from(new Product()). Product p = new Product();
selectCountStar(); List<Integer> lengths = db.from(p).
where(length(p.productName)).smaller(10).
orderBy(1).
selectDistinct(length(p.productName));
String s = lengths.toString();
assertEquals("[4, 5, 7, 8, 9]", s);
}
private void testCount() throws Exception {
long count = db.from(new Product()).selectCount();
assertEquals(77, count); assertEquals(77, count);
} }
//## Java 1.5 end ## //## Java 1.5 end ##
/** /**
* A result set class containing customer data and the order total. * A result set class containing product groups.
*/ */
//## Java 1.5 begin ## //## Java 1.5 begin ##
public static class OrderGroup { public static class ProductGroup {
public String category; public String category;
public Long productCount; public Long productCount;
} }
...@@ -280,17 +297,17 @@ public class SamplesTest extends TestBase { ...@@ -280,17 +297,17 @@ public class SamplesTest extends TestBase {
// }; // };
final Product p = new Product(); final Product p = new Product();
List<OrderGroup> list = List<ProductGroup> list =
db.from(p). db.from(p).
groupBy(p.category). groupBy(p.category).
orderBy(1). orderBy(1).
select(new OrderGroup() { { select(new ProductGroup() { {
category = p.category; category = p.category;
productCount = countStar(); productCount = count();
}}); }});
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
for (OrderGroup og: list) { for (ProductGroup og: list) {
buff.append(og.category); buff.append(og.category);
buff.append("="); buff.append("=");
buff.append(og.productCount); buff.append(og.productCount);
......
...@@ -12,7 +12,7 @@ package org.h2.jaqu; ...@@ -12,7 +12,7 @@ package org.h2.jaqu;
* @param <A> the operand type * @param <A> the operand type
*/ */
//## Java 1.5 begin ## //## Java 1.5 begin ##
class Condition<A> implements ConditionToken { class Condition<A> implements Token {
Query< ? > query; Query< ? > query;
CompareType compareType; CompareType compareType;
A x, y; A x, y;
...@@ -24,7 +24,7 @@ class Condition<A> implements ConditionToken { ...@@ -24,7 +24,7 @@ class Condition<A> implements ConditionToken {
this.y = y; this.y = y;
} }
public String getString() { public String getString(Query query) {
if (compareType.hasRightExpression()) { if (compareType.hasRightExpression()) {
return query.getString(x) + compareType.getString() + query.getString(y); return query.getString(x) + compareType.getString() + query.getString(y);
} }
......
...@@ -10,7 +10,7 @@ package org.h2.jaqu; ...@@ -10,7 +10,7 @@ package org.h2.jaqu;
* An OR or an AND condition. * An OR or an AND condition.
*/ */
//## Java 1.5 begin ## //## Java 1.5 begin ##
enum ConditionAndOr implements ConditionToken { enum ConditionAndOr implements Token {
AND("AND"), AND("AND"),
OR("OR"); OR("OR");
...@@ -20,7 +20,7 @@ enum ConditionAndOr implements ConditionToken { ...@@ -20,7 +20,7 @@ enum ConditionAndOr implements ConditionToken {
this.text = text; this.text = text;
} }
public String getString() { public String getString(Query query) {
return text; return text;
} }
......
...@@ -16,6 +16,7 @@ import java.util.Map; ...@@ -16,6 +16,7 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.h2.jaqu.util.Utils; import org.h2.jaqu.util.Utils;
import org.h2.jaqu.util.WeakIdentityHashMap;
import org.h2.util.JdbcUtils; import org.h2.util.JdbcUtils;
//## Java 1.5 end ## //## Java 1.5 end ##
...@@ -25,6 +26,8 @@ import org.h2.util.JdbcUtils; ...@@ -25,6 +26,8 @@ import org.h2.util.JdbcUtils;
//## Java 1.5 begin ## //## Java 1.5 begin ##
public class Db { public class Db {
private static final WeakIdentityHashMap<Object, Token> TOKENS = Utils.newWeakIdentityHashMap();
private final Connection conn; private final Connection conn;
private final Map<Class, TableDefinition> classMap = Utils.newHashMap(); private final Map<Class, TableDefinition> classMap = Utils.newHashMap();
...@@ -32,6 +35,15 @@ public class Db { ...@@ -32,6 +35,15 @@ public class Db {
this.conn = conn; this.conn = conn;
} }
static <X> X registerToken(X x, Token token) {
TOKENS.put(x, token);
return x;
}
static Token getToken(Object x) {
return TOKENS.get(x);
}
private static <T> T instance(Class<T> clazz) { private static <T> T instance(Class<T> clazz) {
try { try {
return clazz.newInstance(); return clazz.newInstance();
......
...@@ -6,15 +6,55 @@ ...@@ -6,15 +6,55 @@
*/ */
package org.h2.jaqu; package org.h2.jaqu;
//## Java 1.5 begin ##
import org.h2.jaqu.util.Utils;
//## Java 1.5 end ##
/** /**
* This class provides static methods that represents common SQL functions. * This class provides static methods that represents common SQL functions.
*/ */
public class Function { public class Function implements Token {
//## Java 1.5 begin ##
private static final Long COUNT_STAR = new Long(0); private static final Long COUNT_STAR = new Long(0);
public static Long countStar() { private String name;
private Object x;
private Function(String name, Object x) {
this.name = name;
this.x = x;
}
public String getString(Query query) {
return name + "(" + query.getString(x) + ")";
}
//## Java 1.5 end ##
public static Long count() {
return COUNT_STAR; return COUNT_STAR;
} }
public static Integer length(Object x) {
return Db.registerToken(Utils.newObject(Integer.class), new Function("LENGTH", x));
}
public static Long count(Object x) {
return Db.registerToken(Utils.newObject(Long.class), new Function("COUNT", x));
}
public static <X> X min(X x) {
Class<X> clazz = (Class<X>) x.getClass();
X o = Utils.newObject(clazz);
return Db.registerToken(o, new Function("MIN", x));
}
public static <X> X max(X x) {
Class<X> clazz = (Class<X>) x.getClass();
X o = Utils.newObject(clazz);
return Db.registerToken(o, new Function("MAX", x));
}
//## Java 1.5 end ##
} }
...@@ -26,7 +26,7 @@ public class Query<T> { ...@@ -26,7 +26,7 @@ public class Query<T> {
private Db db; private Db db;
private SelectTable<T> from; private SelectTable<T> from;
private ArrayList<ConditionToken> conditions = Utils.newArrayList(); private ArrayList<Token> conditions = Utils.newArrayList();
private ArrayList<SelectTable> joins = Utils.newArrayList(); private ArrayList<SelectTable> joins = Utils.newArrayList();
private final HashMap<Object, SelectColumn> aliasMap = Utils.newHashMap(); private final HashMap<Object, SelectColumn> aliasMap = Utils.newHashMap();
private ArrayList<OrderExpression> orderByList = Utils.newArrayList(); private ArrayList<OrderExpression> orderByList = Utils.newArrayList();
...@@ -44,8 +44,8 @@ public class Query<T> { ...@@ -44,8 +44,8 @@ public class Query<T> {
return query; return query;
} }
public long selectCountStar() { public long selectCount() {
ResultSet rs = db.executeQuery(getString("COUNT(*)")); ResultSet rs = db.executeQuery(getSQL("COUNT(*)", false));
try { try {
rs.next(); rs.next();
long value = rs.getLong(1); long value = rs.getLong(1);
...@@ -56,8 +56,16 @@ public class Query<T> { ...@@ -56,8 +56,16 @@ public class Query<T> {
} }
public List<T> select() { public List<T> select() {
return select(false);
}
public List<T> selectDistinct() {
return select(true);
}
private List<T> select(boolean distinct) {
List<T> result = Utils.newArrayList(); List<T> result = Utils.newArrayList();
ResultSet rs = db.executeQuery(getString("*")); ResultSet rs = db.executeQuery(getSQL("*", distinct));
try { try {
while (rs.next()) { while (rs.next()) {
T item = from.newObject(); T item = from.newObject();
...@@ -70,19 +78,27 @@ public class Query<T> { ...@@ -70,19 +78,27 @@ public class Query<T> {
return result; return result;
} }
public <X, Z> List<X> selectDistinct(Z x) {
return select(x, true);
}
public <X, Z> List<X> select(Z x) { public <X, Z> List<X> select(Z x) {
return select(x, false);
}
private <X, Z> List<X> select(Z x, boolean distinct) {
Class< ? > clazz = x.getClass(); Class< ? > clazz = x.getClass();
if (Utils.isSimpleType(clazz)) { if (Utils.isSimpleType(clazz)) {
return selectSimple((X) x); return getSimple((X) x, distinct);
} }
clazz = clazz.getSuperclass(); clazz = clazz.getSuperclass();
return select((Class<X>) clazz, (X) x); return select((Class<X>) clazz, (X) x, distinct);
} }
private <X> List<X> select(Class<X> clazz, X x) { private <X> List<X> select(Class<X> clazz, X x, boolean distinct) {
TableDefinition<X> def = db.define(clazz); TableDefinition<X> def = db.define(clazz);
String selectList = def.getSelectList(this, x); String selectList = def.getSelectList(this, x);
ResultSet rs = db.executeQuery(getString(selectList)); ResultSet rs = db.executeQuery(getSQL(selectList, distinct));
List<X> result = Utils.newArrayList(); List<X> result = Utils.newArrayList();
try { try {
while (rs.next()) { while (rs.next()) {
...@@ -96,9 +112,9 @@ public class Query<T> { ...@@ -96,9 +112,9 @@ public class Query<T> {
return result; return result;
} }
private <X> List<X> selectSimple(X x) { private <X> List<X> getSimple(X x, boolean distinct) {
String selectList = getString(x); String selectList = getString(x);
ResultSet rs = db.executeQuery(getString(selectList)); ResultSet rs = db.executeQuery(getSQL(selectList, distinct));
List<X> result = Utils.newArrayList(); List<X> result = Utils.newArrayList();
try { try {
while (rs.next()) { while (rs.next()) {
...@@ -135,45 +151,25 @@ public class Query<T> { ...@@ -135,45 +151,25 @@ public class Query<T> {
return this; return this;
} }
public Query<T> orderByNullsFirst(Object expr) {
OrderExpression<Object> e = new OrderExpression<Object>(this, expr, false, true, false);
addOrderBy(e);
return this;
}
public Query<T> orderByNullsLast(Object expr) {
OrderExpression<Object> e = new OrderExpression<Object>(this, expr, false, false, true);
addOrderBy(e);
return this;
}
public Query<T> orderByDesc(Object expr) { public Query<T> orderByDesc(Object expr) {
OrderExpression<Object> e = new OrderExpression<Object>(this, expr, true, false, false); OrderExpression<Object> e = new OrderExpression<Object>(this, expr, true, false, false);
addOrderBy(e); addOrderBy(e);
return this; return this;
} }
public Query<T> orderByDescNullsFirst(Object expr) {
OrderExpression<Object> e = new OrderExpression<Object>(this, expr, true, true, false);
addOrderBy(e);
return this;
}
public Query<T> orderByDescNullsLast(Object expr) {
OrderExpression<Object> e = new OrderExpression<Object>(this, expr, true, false, true);
addOrderBy(e);
return this;
}
public Query<T> groupBy(Object... groupByExpressions) { public Query<T> groupBy(Object... groupByExpressions) {
this.groupByExpressions = groupByExpressions; this.groupByExpressions = groupByExpressions;
return this; return this;
} }
String getString(Object x) { String getString(Object x) {
if (x == Function.countStar()) { if (x == Function.count()) {
return "COUNT(*)"; return "COUNT(*)";
} }
Token token = Db.getToken(x);
if (token != null) {
return token.getString(this);
}
SelectColumn col = aliasMap.get(x); SelectColumn col = aliasMap.get(x);
if (col != null) { if (col != null) {
return col.getString(); return col.getString();
...@@ -181,22 +177,25 @@ public class Query<T> { ...@@ -181,22 +177,25 @@ public class Query<T> {
return Utils.quoteSQL(x); return Utils.quoteSQL(x);
} }
void addConditionToken(ConditionToken condition) { void addConditionToken(Token condition) {
conditions.add(condition); conditions.add(condition);
} }
String getString(String selectList) { String getSQL(String selectList, boolean distinct) {
StringBuilder buff = new StringBuilder("SELECT "); StringBuilder buff = new StringBuilder("SELECT ");
if (distinct) {
buff.append("DISTINCT ");
}
buff.append(selectList); buff.append(selectList);
buff.append(" FROM "); buff.append(" FROM ");
buff.append(from.getString()); buff.append(from.getString());
for (SelectTable join : joins) { for (SelectTable join : joins) {
buff.append(join.getStringAsJoin()); buff.append(join.getStringAsJoin(this));
} }
if (!conditions.isEmpty()) { if (!conditions.isEmpty()) {
buff.append(" WHERE "); buff.append(" WHERE ");
for (ConditionToken token : conditions) { for (Token token : conditions) {
buff.append(token.getString()); buff.append(token.getString(this));
buff.append(' '); buff.append(' ');
} }
} }
......
/* /*
* Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License, * Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0 * Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.jaqu; package org.h2.jaqu;
/** /**
* This class represents a query with an incomplete condition. * This class represents a query with an incomplete condition.
* *
* @param <T> the return type of the query * @param <T> the return type of the query
* @param <A> the incomplete condition data type * @param <A> the incomplete condition data type
*/ */
//## Java 1.5 begin ## //## Java 1.5 begin ##
public class QueryCondition<T, A> { public class QueryCondition<T, A> {
private Query<T> query; private Query<T> query;
private A x; private A x;
QueryCondition(Query<T> query, A x) { QueryCondition(Query<T> query, A x) {
this.query = query; this.query = query;
this.x = x; this.x = x;
} }
public QueryWhere<T> is(A y) { public QueryWhere<T> is(A y) {
query.addConditionToken(new Condition<A>(query, x, y, CompareType.EQUAL)); query.addConditionToken(new Condition<A>(query, x, y, CompareType.EQUAL));
return new QueryWhere<T>(query); return new QueryWhere<T>(query);
} }
public QueryWhere<T> bigger(A y) { public QueryWhere<T> bigger(A y) {
query.addConditionToken(new Condition<A>(query, x, y, CompareType.BIGGER)); query.addConditionToken(new Condition<A>(query, x, y, CompareType.BIGGER));
return new QueryWhere<T>(query); return new QueryWhere<T>(query);
} }
public QueryWhere<T> smaller(A y) { public QueryWhere<T> smaller(A y) {
query.addConditionToken(new Condition<A>(query, x, y, CompareType.SMALLER)); query.addConditionToken(new Condition<A>(query, x, y, CompareType.SMALLER));
return new QueryWhere<T>(query); return new QueryWhere<T>(query);
} }
} }
//## Java 1.5 end ## //## Java 1.5 end ##
...@@ -38,9 +38,18 @@ public class QueryWhere<T> { ...@@ -38,9 +38,18 @@ public class QueryWhere<T> {
return (List<X>) query.select(x); return (List<X>) query.select(x);
} }
public <X, Z> List<X> selectDistinct(Z x) {
return (List<X>) query.selectDistinct(x);
}
public List<T> select() { public List<T> select() {
return query.select(); return query.select();
} }
public List<T> selectDistinct() {
return query.selectDistinct();
}
//## Java 1.5 end ## //## Java 1.5 end ##
/** /**
......
...@@ -6,9 +6,9 @@ ...@@ -6,9 +6,9 @@
*/ */
package org.h2.jaqu; package org.h2.jaqu;
//## Java 1.5 begin ##
import java.util.ArrayList; import java.util.ArrayList;
//## Java 1.5 begin ##
import org.h2.jaqu.util.ClassUtils; import org.h2.jaqu.util.ClassUtils;
import org.h2.jaqu.util.Utils; import org.h2.jaqu.util.Utils;
//## Java 1.5 end ## //## Java 1.5 end ##
...@@ -28,7 +28,7 @@ class SelectTable <T> { ...@@ -28,7 +28,7 @@ class SelectTable <T> {
private String as; private String as;
private TableDefinition<T> aliasDef; private TableDefinition<T> aliasDef;
private boolean outerJoin; private boolean outerJoin;
private ArrayList<ConditionToken> joinConditions = Utils.newArrayList(); private ArrayList<Token> joinConditions = Utils.newArrayList();
SelectTable(Db db, Query query, T alias, boolean outerJoin) { SelectTable(Db db, Query query, T alias, boolean outerJoin) {
this.query = query; this.query = query;
...@@ -53,7 +53,7 @@ class SelectTable <T> { ...@@ -53,7 +53,7 @@ class SelectTable <T> {
return aliasDef.tableName; return aliasDef.tableName;
} }
String getStringAsJoin() { String getStringAsJoin(Query query) {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
if (outerJoin) { if (outerJoin) {
buff.append(" LEFT OUTER JOIN "); buff.append(" LEFT OUTER JOIN ");
...@@ -63,8 +63,8 @@ class SelectTable <T> { ...@@ -63,8 +63,8 @@ class SelectTable <T> {
buff.append(getString()); buff.append(getString());
if (!joinConditions.isEmpty()) { if (!joinConditions.isEmpty()) {
buff.append(" ON "); buff.append(" ON ");
for (ConditionToken token : joinConditions) { for (Token token : joinConditions) {
buff.append(token.getString()); buff.append(token.getString(query));
buff.append(' '); buff.append(' ');
} }
} }
...@@ -83,7 +83,7 @@ class SelectTable <T> { ...@@ -83,7 +83,7 @@ class SelectTable <T> {
return as; return as;
} }
void addConditionToken(ConditionToken condition) { void addConditionToken(Token condition) {
joinConditions.add(condition); joinConditions.add(condition);
} }
......
...@@ -7,9 +7,10 @@ ...@@ -7,9 +7,10 @@
package org.h2.jaqu; package org.h2.jaqu;
/** /**
* Classes implementing this interface can be used as a token in a conditional * Classes implementing this interface can be used as a token in a statement.
* expression.
*/ */
interface ConditionToken { interface Token {
String getString(); //## Java 1.5 begin ##
String getString(Query query);
//## Java 1.5 end ##
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论