This commit is contained in:
Timo Westkämper 2009-05-25 19:28:27 +00:00
parent f9aede527e
commit 0fbae15854
6 changed files with 309 additions and 219 deletions

View File

@ -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<SubType extends BaseSerializer<SubType>> extends AbstractVisitor<SubType>{
protected StringBuilder builder = new StringBuilder();
protected final List<Object> constants = new ArrayList<Object>();
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<? extends Expr<?>> 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<Object> getConstants(){
return constants;
}
public String toString(){ return builder.toString(); }
public abstract class BaseSerializer<SubType extends BaseSerializer<SubType>>
extends AbstractVisitor<SubType> {
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.<Expr<?>>singletonList(q.getTarget()));
}
protected StringBuilder builder = new StringBuilder();
@Override
protected void visit(ASimple<?> expr) {
throw new UnsupportedOperationException("not implemented");
}
protected final List<Object> constants = new ArrayList<Object>();
@Override
protected void visit(AToPath expr) {
throw new UnsupportedOperationException("not implemented");
}
protected void visitOperation(Class<?> type, Op<?> operator, List<Expr<?>> 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<Object> getConstants() {
return constants;
}
public final SubType handle(String sep, List<? extends Expr<?>> 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.<Expr<?>> singletonList(q.getTarget()));
}
protected void visitOperation(Class<?> type, Op<?> operator,List<Expr<?>> 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));
}
}

View File

@ -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<Object, JDOQLQueryImpl> 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<Object, JDOQLQueryImpl> 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<Object, JDOQLQueryImpl> 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<Object, JDOQLQueryImpl> imp
query.setRange(fromIncl, toExcl);
}
// projection
if (!getMetadata().getProjection().isEmpty()){
// projection (not for count)
if (!getMetadata().getProjection().isEmpty() && !forCount){
List<? extends Expr<?>> 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<Object, JDOQLQueryImpl> imp
}
}
// order
// TODO
// order (not for count)
if (!getMetadata().getOrderBy().isEmpty() && !forCount){
List<OrderSpecifier<?>> 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<Object, JDOQLQueryImpl> imp
addToProjection(expr1, expr2);
addToProjection(rest);
String filterString = getFilterString();
return (List<Object[]>) execute(createQuery(filterString, getMetadata().getModifiers()));
return (List<Object[]>) execute(createQuery(filterString, getMetadata().getModifiers(), false));
}
private Object execute(Query query){
@ -201,20 +215,20 @@ class JDOQLQueryImpl extends QueryBaseWithProjection<Object, JDOQLQueryImpl> imp
addToProjection(expr);
String filterString = getFilterString();
logger.debug("query : {}", filterString);
return (List<RT>) execute(createQuery(filterString, getMetadata().getModifiers()));
return (List<RT>) execute(createQuery(filterString, getMetadata().getModifiers(), false));
}
@SuppressWarnings("unchecked")
public <RT> SearchResults<RT> listResults(Expr<RT> 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<RT> list = (List<RT>) execute(query);
return new SearchResults<RT>(list, modifiers, total);
} else {
@ -234,7 +248,7 @@ class JDOQLQueryImpl extends QueryBaseWithProjection<Object, JDOQLQueryImpl> 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);
}

View File

@ -59,23 +59,16 @@ public class JDOQLSerializer extends BaseSerializer<JDOQLSerializer> {
}
}
// 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<Expr<?>> args) {
if (operator.equals(Ops.ISTYPEOF)){
handle(args.get(0)).append(" instanceof ");
append(((EConstant<Class<?>>)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);
}

View File

@ -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("");
}
}

View File

@ -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("");
}
}

View File

@ -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<String> 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<String> 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("");
}
}