From 0fbae15854ea6dca4752554a1bc096c3bb4ab8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timo=20Westk=C3=A4mper?= Date: Mon, 25 May 2009 19:28:27 +0000 Subject: [PATCH] --- .../query/serialization/BaseSerializer.java | 291 +++++++++--------- .../mysema/query/jdoql/JDOQLQueryImpl.java | 46 ++- .../mysema/query/jdoql/JDOQLSerializer.java | 13 +- .../mysema/query/jdoql/AbstractJDOTest.java | 40 +-- ...JDOQueryTest.java => QueryBasicsTest.java} | 57 +++- .../mysema/query/jdoql/QueryOrderingTest.java | 81 +++++ 6 files changed, 309 insertions(+), 219 deletions(-) rename querydsl-jdoql/src/test/java/com/mysema/query/jdoql/{JDOQueryTest.java => QueryBasicsTest.java} (72%) create mode 100644 querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryOrderingTest.java diff --git a/querydsl-core/src/main/java/com/mysema/query/serialization/BaseSerializer.java b/querydsl-core/src/main/java/com/mysema/query/serialization/BaseSerializer.java index b6af2deaa..4f31d84d9 100644 --- a/querydsl-core/src/main/java/com/mysema/query/serialization/BaseSerializer.java +++ b/querydsl-core/src/main/java/com/mysema/query/serialization/BaseSerializer.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import com.mysema.commons.lang.Assert; import com.mysema.query.types.AbstractVisitor; import com.mysema.query.types.alias.ASimple; import com.mysema.query.types.alias.AToPath; @@ -30,150 +31,160 @@ import com.mysema.query.types.quant.Quant; /** * BaseSerializer is a stub for Serializer implementations - * + * * @author tiwe * @version $Id$ */ -public abstract class BaseSerializer> extends AbstractVisitor{ - - protected StringBuilder builder = new StringBuilder(); - - protected final List constants = new ArrayList(); - - protected final OperationPatterns ops; - - @SuppressWarnings("unchecked") - private final SubType _this = (SubType)this; - - public BaseSerializer(OperationPatterns ops){ - if (ops == null) throw new IllegalArgumentException("ops was null"); - this.ops = ops; - } - - protected final SubType append(String... str) { - for (String s : str){ - builder.append(s); - } - return _this; - } - - public final SubType handle(String sep, List> expressions) { - boolean first = true; - for (Expr expr : expressions){ - if (!first) builder.append(sep); - handle(expr); first = false; - } - return _this; - } - - protected void visit(Path path) { - PathType pathType = path.getMetadata().getPathType(); - String parentAsString = null, exprAsString = null; - - if (path.getMetadata().getParent() != null){ - parentAsString = toString((Expr)path.getMetadata().getParent(),false); - } - if (pathType == PROPERTY || pathType == VARIABLE || pathType == LISTVALUE_CONSTANT || pathType == ARRAYVALUE_CONSTANT){ - exprAsString = path.getMetadata().getExpression().toString(); - }else if (path.getMetadata().getExpression() != null){ - exprAsString = toString(path.getMetadata().getExpression(),false); - } - - String pattern = ops.getPattern(pathType); - if (parentAsString != null){ - append(String.format(pattern, parentAsString, exprAsString)); - }else{ - append(String.format(pattern, exprAsString)); - } - - } - - protected final String toString(Expr expr, boolean wrap) { - StringBuilder old = builder; - builder = new StringBuilder(); - if (wrap) builder.append("("); - handle(expr); - if (wrap) builder.append(")"); - String ret = builder.toString(); - builder = old; - return ret; - } - - protected void visit(Custom expr){ - Object[] strings = new String[expr.getArgs().size()]; - for (int i = 0; i < strings.length; i++){ - strings[i] = toString(expr.getArg(i),false); - } - append(String.format(expr.getPattern(), strings)); - } - - public List getConstants(){ - return constants; - } - - public String toString(){ return builder.toString(); } +public abstract class BaseSerializer> + extends AbstractVisitor { - protected void visit(EConstructor expr){ - append("new ").append(expr.getType().getName()).append("("); - handle(", ",expr.getArgs()).append(")"); - } - - @Override - protected void visit(EConstant expr) { - append("a"); - if (!constants.contains(expr.getConstant())){ - constants.add(expr.getConstant()); - append(Integer.toString(constants.size())); - }else{ - append(Integer.toString(constants.indexOf(expr.getConstant())+1)); - } - } - - protected void visit(EArrayConstructor oa) { -// _append("new Object[]{"); - append("new ").append(oa.getElementType().getName()).append("[]{"); - handle(", ",oa.getArgs()).append("}"); - } - - @Override - protected final void visit(Operation expr) { - visitOperation(expr.getType(), expr.getOperator(), expr.getArgs()); - } - - protected void visit(Quant q){ - visitOperation(null, q.getOperator(), Collections.>singletonList(q.getTarget())); - } + protected StringBuilder builder = new StringBuilder(); - - @Override - protected void visit(ASimple expr) { - throw new UnsupportedOperationException("not implemented"); - } + protected final List constants = new ArrayList(); - @Override - protected void visit(AToPath expr) { - throw new UnsupportedOperationException("not implemented"); - } - - protected void visitOperation(Class type, Op operator, List> args) { - String pattern = ops.getPattern(operator); - if (pattern == null) - throw new IllegalArgumentException("Got no pattern for " + operator); - Object[] strings = new String[args.size()]; - int precedence = ops.getPrecedence(operator); - for (int i = 0; i < strings.length; i++){ - boolean wrap = false; - if (args.get(i) instanceof Operation){ - // wrap if outer operator precedes - wrap = precedence < ops.getPrecedence(((Operation)args.get(i)).getOperator()); - } - strings[i] = toString(args.get(i),wrap); - } - // TODO : use faster custom rendering - appendOperationResult(operator, String.format(pattern, strings)); - } - - protected void appendOperationResult(Op operator, String result){ - append(result); - } + protected final OperationPatterns ops; + + @SuppressWarnings("unchecked") + private final SubType _this = (SubType) this; + + public BaseSerializer(OperationPatterns ops) { + this.ops = Assert.notNull(ops); + } + + public final SubType append(String... str) { + for (String s : str) { + builder.append(s); + } + return _this; + } + + protected void appendOperationResult(Op operator, String result) { + append(result); + } + + public List getConstants() { + return constants; + } + + public final SubType handle(String sep, List> expressions) { + boolean first = true; + for (Expr expr : expressions) { + if (!first){ + builder.append(sep); + } + handle(expr); + first = false; + } + return _this; + } + + public String toString() { + return builder.toString(); + } + + protected final String toString(Expr expr, boolean wrap) { + StringBuilder old = builder; + builder = new StringBuilder(); + if (wrap){ + builder.append("("); + } + handle(expr); + if (wrap){ + builder.append(")"); + } + String ret = builder.toString(); + builder = old; + return ret; + } + + @Override + protected void visit(ASimple expr) { + throw new UnsupportedOperationException("not implemented"); + } + + @Override + protected void visit(AToPath expr) { + throw new UnsupportedOperationException("not implemented"); + } + + protected void visit(Custom expr) { + Object[] strings = new String[expr.getArgs().size()]; + for (int i = 0; i < strings.length; i++) { + strings[i] = toString(expr.getArg(i), false); + } + append(String.format(expr.getPattern(), strings)); + } + + protected void visit(EArrayConstructor oa) { + append("new ").append(oa.getElementType().getName()).append("[]{"); + handle(", ", oa.getArgs()).append("}"); + } + + @Override + protected void visit(EConstant expr) { + append("a"); + if (!constants.contains(expr.getConstant())) { + constants.add(expr.getConstant()); + append(Integer.toString(constants.size())); + } else { + append(Integer.toString(constants.indexOf(expr.getConstant()) + 1)); + } + } + + protected void visit(EConstructor expr) { + append("new ").append(expr.getType().getName()).append("("); + handle(", ", expr.getArgs()).append(")"); + } + + @Override + protected final void visit(Operation expr) { + visitOperation(expr.getType(), expr.getOperator(), expr.getArgs()); + } + + protected void visit(Path path) { + PathType pathType = path.getMetadata().getPathType(); + String parentAsString = null, exprAsString = null; + + if (path.getMetadata().getParent() != null) { + parentAsString = toString((Expr) path.getMetadata().getParent(), false); + } + if (pathType == PROPERTY || pathType == VARIABLE + || pathType == LISTVALUE_CONSTANT + || pathType == ARRAYVALUE_CONSTANT) { + exprAsString = path.getMetadata().getExpression().toString(); + } else if (path.getMetadata().getExpression() != null) { + exprAsString = toString(path.getMetadata().getExpression(), false); + } + + String pattern = ops.getPattern(pathType); + if (parentAsString != null) { + append(String.format(pattern, parentAsString, exprAsString)); + } else { + append(String.format(pattern, exprAsString)); + } + + } + + protected void visit(Quant q) { + visitOperation(null, q.getOperator(), Collections.> singletonList(q.getTarget())); + } + + protected void visitOperation(Class type, Op operator,List> args) { + String pattern = ops.getPattern(operator); + if (pattern == null){ + throw new IllegalArgumentException("Got no pattern for " + operator); + } + Object[] strings = new String[args.size()]; + int precedence = ops.getPrecedence(operator); + for (int i = 0; i < strings.length; i++) { + boolean wrap = false; + if (args.get(i) instanceof Operation) { + // wrap if outer operator precedes + wrap = precedence < ops.getPrecedence(((Operation) args.get(i)).getOperator()); + } + strings[i] = toString(args.get(i), wrap); + } + // TODO : use faster custom rendering + appendOperationResult(operator, String.format(pattern, strings)); + } } diff --git a/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLQueryImpl.java b/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLQueryImpl.java index 01c4df45a..165fefefd 100644 --- a/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLQueryImpl.java +++ b/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLQueryImpl.java @@ -19,6 +19,8 @@ import com.mysema.query.Projectable; import com.mysema.query.QueryModifiers; import com.mysema.query.SearchResults; import com.mysema.query.support.QueryBaseWithProjection; +import com.mysema.query.types.Order; +import com.mysema.query.types.OrderSpecifier; import com.mysema.query.types.expr.EConstructor; import com.mysema.query.types.expr.Expr; import com.mysema.query.types.path.PEntity; @@ -81,7 +83,6 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp return null; } JDOQLSerializer serializer = new JDOQLSerializer(ops, sources.get(0)); - // NOTE : serializes only the constraints serializer.handle(getMetadata().getWhere()); constants = serializer.getConstants(); System.err.println("SERIALIZED : " + serializer.toString()); @@ -97,13 +98,13 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp public long count(){ String filterString = getFilterString(); logger.debug("query : {}", filterString); - Query query = createQuery(filterString, QueryModifiers.limit(1)); + Query query = createQuery(filterString, null, true); query.setUnique(true); query.setResult("count(this)"); return (Long) execute(query); } - private Query createQuery(String filterString, QueryModifiers modifiers) { + private Query createQuery(String filterString, QueryModifiers modifiers, boolean forCount) { Query query = pm.newQuery(sources.get(0).getType()); if (filterString != null){ query.setFilter(filterString); @@ -134,8 +135,8 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp query.declareParameters(builder.toString()); } - // range - if (modifiers.isRestricting()){ + // range (not for count) + if (modifiers != null && modifiers.isRestricting() && !forCount){ long fromIncl = 0; long toExcl = Long.MAX_VALUE; if (modifiers.getOffset() != null){ @@ -147,8 +148,8 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp query.setRange(fromIncl, toExcl); } - // projection - if (!getMetadata().getProjection().isEmpty()){ + // projection (not for count) + if (!getMetadata().getProjection().isEmpty() && !forCount){ List> projection = getMetadata().getProjection(); if (!projection.get(0).equals(sources.get(0))){ JDOQLSerializer serializer = new JDOQLSerializer(ops, sources.get(0)); @@ -157,8 +158,21 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp } } - // order - // TODO + // order (not for count) + if (!getMetadata().getOrderBy().isEmpty() && !forCount){ + List> order = getMetadata().getOrderBy(); + JDOQLSerializer serializer = new JDOQLSerializer(ops, sources.get(0)); + boolean first = true; + for (OrderSpecifier os : order){ + if (!first){ + serializer.append(", "); + } + serializer.handle(os.getTarget()); + serializer.append(os.getOrder() == Order.ASC ? " ascending" : "descending"); + first = false; + } + query.setOrdering(serializer.toString()); + } return query; } @@ -182,7 +196,7 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp addToProjection(expr1, expr2); addToProjection(rest); String filterString = getFilterString(); - return (List) execute(createQuery(filterString, getMetadata().getModifiers())); + return (List) execute(createQuery(filterString, getMetadata().getModifiers(), false)); } private Object execute(Query query){ @@ -201,20 +215,20 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp addToProjection(expr); String filterString = getFilterString(); logger.debug("query : {}", filterString); - return (List) execute(createQuery(filterString, getMetadata().getModifiers())); + return (List) execute(createQuery(filterString, getMetadata().getModifiers(), false)); } @SuppressWarnings("unchecked") public SearchResults listResults(Expr expr) { addToProjection(expr); - Query query = createQuery(getFilterString(),null); - query.setUnique(true); - long total = (Long) execute(query); + Query countQuery = createQuery(getFilterString(), null, true); + countQuery.setUnique(true); + long total = (Long) execute(countQuery); if (total > 0) { QueryModifiers modifiers = getMetadata().getModifiers(); String filterString = getFilterString(); logger.debug("query : {}", filterString); - query = createQuery(filterString, modifiers); + Query query = createQuery(filterString, modifiers,false); List list = (List) execute(query); return new SearchResults(list, modifiers, total); } else { @@ -234,7 +248,7 @@ class JDOQLQueryImpl extends QueryBaseWithProjection imp addToProjection(expr); String filterString = getFilterString(); logger.debug("query : {}", filterString); - Query query = createQuery(filterString, QueryModifiers.limit(1)); + Query query = createQuery(filterString, QueryModifiers.limit(1),false); query.setUnique(true); return (RT) execute(query); } diff --git a/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLSerializer.java b/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLSerializer.java index 9f5cdd661..eaf72a6f5 100644 --- a/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLSerializer.java +++ b/querydsl-jdoql/src/main/java/com/mysema/query/jdoql/JDOQLSerializer.java @@ -59,23 +59,16 @@ public class JDOQLSerializer extends BaseSerializer { } } - // FIXME - private void visitCast(Op operator, Expr source, Class targetType) { - append("CAST(").handle(source); - append(" AS "); - append(targetType.getSimpleName().toLowerCase()).append(")"); - - } - + @SuppressWarnings("unchecked") @Override protected void visitOperation(Class type, Op operator, List> args) { if (operator.equals(Ops.ISTYPEOF)){ handle(args.get(0)).append(" instanceof "); append(((EConstant>)args.get(1)).getConstant().getName()); }else if (operator.equals(Ops.STRING_CAST)) { - visitCast(operator, args.get(0), String.class); + // TODO } else if (operator.equals(Ops.NUMCAST)) { - visitCast(operator, args.get(0), (Class) ((EConstant) args.get(1)).getConstant()); + // TODO } else { super.visitOperation(type, operator, args); } diff --git a/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/AbstractJDOTest.java b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/AbstractJDOTest.java index 85207aa67..2a0072e78 100644 --- a/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/AbstractJDOTest.java +++ b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/AbstractJDOTest.java @@ -11,12 +11,8 @@ import javax.jdo.Transaction; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; -import com.mysema.query.jdoql.testdomain.Book; import com.mysema.query.jdoql.testdomain.Product; -import com.mysema.query.jdoql.testdomain.QBook; -import com.mysema.query.jdoql.testdomain.QProduct; import com.mysema.query.types.expr.EBoolean; import com.mysema.query.types.path.PEntity; @@ -24,12 +20,8 @@ public abstract class AbstractJDOTest { protected static PersistenceManagerFactory pmf = JDOHelper.getPersistenceManagerFactory("datanucleus.properties"); - protected QBook book = QBook.book; - protected PersistenceManager pm; - protected QProduct product = QProduct.product; - protected Transaction tx; protected JDOQLQuery query(){ @@ -75,36 +67,6 @@ public abstract class AbstractJDOTest { pm.close(); } } - - @BeforeClass - public static void doPersist() { - // Persistence of a Product and a Book. - PersistenceManager pm = pmf.getPersistenceManager(); - Transaction tx = pm.currentTransaction(); - try { - tx.begin(); - System.out.println("Persisting products"); - pm.makePersistent(new Product( - "Sony Discman", - "A standard discman from Sony", - 200.00)); - pm.makePersistent(new Book( - "Lord of the Rings by Tolkien", - "The classic story", - 49.99, - "JRR Tolkien", - "12345678", - "MyBooks Factory")); - tx.commit(); - System.out.println("Product and Book have been persisted"); - } finally { - if (tx.isActive()) { - tx.rollback(); - } - pm.close(); - } - System.out.println(""); - - } + } diff --git a/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/JDOQueryTest.java b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryBasicsTest.java similarity index 72% rename from querydsl-jdoql/src/test/java/com/mysema/query/jdoql/JDOQueryTest.java rename to querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryBasicsTest.java index cdc1a6d54..7f38bf8ef 100644 --- a/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/JDOQueryTest.java +++ b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryBasicsTest.java @@ -2,32 +2,31 @@ package com.mysema.query.jdoql; import static org.junit.Assert.assertEquals; +import javax.jdo.PersistenceManager; +import javax.jdo.Transaction; + +import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import com.mysema.query.jdoql.testdomain.Book; +import com.mysema.query.jdoql.testdomain.Product; +import com.mysema.query.jdoql.testdomain.QBook; +import com.mysema.query.jdoql.testdomain.QProduct; -public class JDOQueryTest extends AbstractJDOTest{ +public class QueryBasicsTest extends AbstractJDOTest{ + private QBook book = QBook.book; + + private QProduct product = QProduct.product; + @Test @Ignore public void countTests(){ // FIXME assertEquals("count", 2, query().from(product).count()); // returns 1, why? } - - @Test - @Ignore - public void searchResults(){ - // TODO - } - - @Test - @Ignore - public void testOrder(){ - // TODO - } - + @Test public void projectionTests(){ assertEquals("Sony Discman", query().from(product) @@ -38,6 +37,7 @@ public class JDOQueryTest extends AbstractJDOTest{ @Test public void basicTests() { assertEquals("list", 2, query().from(product).list(product).size()); + assertEquals("list", 2, query().from(product).list(product.name, product.description).size()); assertEquals("list", 1, query().from(book).list(book).size()); assertEquals("eq", 1, query(product, product.name.eq("Sony Discman")).size()); assertEquals("instanceof ", 1, query(product, product.instanceOf(Book.class)).size()); @@ -95,4 +95,33 @@ public class JDOQueryTest extends AbstractJDOTest{ assertEquals("substring", 1, query(product, product.name.substring(5).eq("Discman")).size()); } + @BeforeClass + public static void doPersist() { + // Persistence of a Product and a Book. + PersistenceManager pm = pmf.getPersistenceManager(); + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + pm.makePersistent(new Product( + "Sony Discman", + "A standard discman from Sony", + 200.00)); + pm.makePersistent(new Book( + "Lord of the Rings by Tolkien", + "The classic story", + 49.99, + "JRR Tolkien", + "12345678", + "MyBooks Factory")); + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + pm.close(); + } + System.out.println(""); + + } + } diff --git a/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryOrderingTest.java b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryOrderingTest.java new file mode 100644 index 000000000..5fc7aea33 --- /dev/null +++ b/querydsl-jdoql/src/test/java/com/mysema/query/jdoql/QueryOrderingTest.java @@ -0,0 +1,81 @@ +package com.mysema.query.jdoql; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import javax.jdo.PersistenceManager; +import javax.jdo.Transaction; + +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import com.mysema.query.jdoql.testdomain.Product; +import com.mysema.query.jdoql.testdomain.QProduct; + +public class QueryOrderingTest extends AbstractJDOTest{ + + private QProduct product = QProduct.product; + + @Test + public void testOrderAsc(){ + List namesAsc = query().from(product) + .orderBy(product.name.asc(), product.description.desc()) + .list(product.name); + assertEquals(30, namesAsc.size()); + String prev = null; + for (String name : namesAsc){ + if (prev != null){ + assertTrue(prev.compareTo(name) < 0); + } + prev = name; + } + } + + @Test + public void testOrderDesc(){ + List namesDesc = query().from(product) + .orderBy(product.name.desc()) + .list(product.name); + assertEquals(30, namesDesc.size()); + String prev = null; + for (String name : namesDesc){ + if (prev != null){ + assertTrue(prev.compareTo(name) > 0); + } + prev = name; + } + } + + @Test + @Ignore + public void searchResults(){ + // TODO + } + + @BeforeClass + public static void doPersist() { + // Persistence of a Product and a Book. + PersistenceManager pm = pmf.getPersistenceManager(); + Transaction tx = pm.currentTransaction(); + try { + tx.begin(); + for (int i=0; i < 10; i++){ + pm.makePersistent(new Product("C"+i,"F"+i, 200.00)); + pm.makePersistent(new Product("B"+i,"E"+i, 200.00)); + pm.makePersistent(new Product("A"+i,"D"+i, 200.00)); + } + tx.commit(); + } finally { + if (tx.isActive()) { + tx.rollback(); + } + pm.close(); + } + System.out.println(""); + + } + +}