#667362 : worked on Collection.any() support

This commit is contained in:
Timo Westkämper 2010-10-28 14:12:17 +00:00
parent 80d96fcdc1
commit 3103dfc715
7 changed files with 149 additions and 12 deletions

View File

@ -16,7 +16,6 @@ import com.mysema.query.QueryException;
import com.mysema.query.QueryMetadata;
import com.mysema.query.SearchResults;
import com.mysema.query.support.ProjectableQuery;
import com.mysema.query.support.QueryMixin;
import com.mysema.query.types.ArrayConstructorExpression;
import com.mysema.query.types.CollectionExpression;
import com.mysema.query.types.Expression;
@ -48,7 +47,7 @@ public abstract class AbstractColQuery<Q extends AbstractColQuery<Q>> extends P
@SuppressWarnings("unchecked")
public AbstractColQuery(QueryMetadata metadata, QueryEngine queryEngine) {
super(new QueryMixin<Q>(metadata));
super(new ColQueryMixin<Q>(metadata));
this.queryMixin.setSelf((Q) this);
this.queryEngine = queryEngine;
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2010 Mysema Ltd.
* All rights reserved.
*
*/
package com.mysema.query.collections;
import com.mysema.query.BooleanBuilder;
import com.mysema.query.QueryMetadata;
import com.mysema.query.support.CollectionAnyVisitor;
import com.mysema.query.support.QueryMixin;
import com.mysema.query.types.CollectionExpression;
import com.mysema.query.types.Path;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.template.BooleanTemplate;
/**
* ColQueryMixin extends QueryMixin
*
* @author tiwe
*
* @param <T>
*/
public class ColQueryMixin<T> extends QueryMixin<T> {
public ColQueryMixin() {}
public ColQueryMixin(QueryMetadata metadata) {
super(metadata);
}
public ColQueryMixin(T self, QueryMetadata metadata) {
super(self, metadata);
}
@Override
protected Predicate[] normalize(Predicate[] conditions, boolean where) {
for (int i = 0; i < conditions.length; i++){
conditions[i] = normalize(conditions[i], where);
}
return conditions;
}
@SuppressWarnings("unchecked")
private Predicate normalize(Predicate predicate, boolean where) {
if (predicate instanceof BooleanBuilder && ((BooleanBuilder)predicate).getValue() == null){
return predicate;
}else{
CollectionAnyVisitor.Context context = new CollectionAnyVisitor.Context();
Predicate transformed = (Predicate) predicate.accept(CollectionAnyVisitor.DEFAULT, context);
for (int i = 0; i < context.anyPaths.size(); i++){
innerJoin(
(CollectionExpression)context.anyPaths.get(i).getMetadata().getParent(),
(Path)context.replacements.get(i));
on(BooleanTemplate.create("any"));
}
return transformed;
}
}
}

View File

@ -63,6 +63,7 @@ public final class ColQueryTemplates extends JavaTemplates {
add(PathType.LISTVALUE_CONSTANT, "{0}.get({1})");
add(PathType.ARRAYVALUE, "{0}[{1}]");
add(PathType.ARRAYVALUE_CONSTANT, "{0}[{1}]");
add(PathType.COLLECTION_ANY, "{0}_any");
// coalesce
add(Ops.COALESCE, functions + ".coalesce({0})");

View File

@ -34,7 +34,10 @@ import com.mysema.query.types.FactoryExpression;
import com.mysema.query.types.Operation;
import com.mysema.query.types.ParamExpression;
import com.mysema.query.types.ParamNotSetException;
import com.mysema.query.types.PathType;
import com.mysema.query.types.Predicate;
import com.mysema.query.types.Templates;
import com.mysema.query.types.ToStringVisitor;
/**
* DefaultEvaluatorFactory extends the EvaluatorFactory class to provide Java source
@ -52,7 +55,7 @@ public class DefaultEvaluatorFactory {
public DefaultEvaluatorFactory(ColQueryTemplates templates){
// TODO : which ClassLoader to pick ?!?
this(templates,
this(templates,
(URLClassLoader)DefaultEvaluatorFactory.class.getClassLoader(),
ToolProvider.getSystemJavaCompiler());
}
@ -148,6 +151,8 @@ public class DefaultEvaluatorFactory {
StringBuilder vars = new StringBuilder();
ColQuerySerializer ser = new ColQuerySerializer(templates);
ser.append("java.util.List<Object[]> rv = new java.util.ArrayList<Object[]>();\n");
List<String> anyJoinMatchers = new ArrayList<String>();
// creating context
for (JoinExpression join : joins){
@ -164,8 +169,12 @@ public class DefaultEvaluatorFactory {
sourceClasses.add(Iterable.class);
}else if (join.getType() == JoinType.INNERJOIN){
Operation alias = (Operation)join.getTarget();
// TODO : handle join condition
Operation alias = (Operation)join.getTarget();
if (join.getCondition() != null && join.getCondition().toString().equals("any")){
String matcher = alias.getArg(1).toString() + "_matched";
ser.append("boolean " + matcher + " = false;\n");
anyJoinMatchers.add(matcher);
}
ser.append("for ( " + typeName + " " + alias.getArg(1) + " : ");
ser.handle(alias.getArg(0));
if (alias.getArg(0).getType().equals(Map.class)){
@ -174,9 +183,6 @@ public class DefaultEvaluatorFactory {
ser.append("){\n");
vars.append(alias.getArg(1));
// }else if (join.getType() == JoinType.LEFTJOIN){
// // TODO
//
}else{
throw new IllegalArgumentException("Illegal join expression " + join);
}
@ -184,7 +190,14 @@ public class DefaultEvaluatorFactory {
// filter
if (filter != null){
ser.append("if (").handle(filter).append("){\n");
ser.append("if (");
for (String matcher : anyJoinMatchers){
ser.append("!" + matcher + " && ");
}
ser.handle(filter).append("){\n");
for (String matcher : anyJoinMatchers){
ser.append(" "+ matcher + " = true;\n");
}
ser.append(" rv.add(new Object[]{"+vars+"});\n");
ser.append("}\n");
}else{

View File

@ -92,7 +92,8 @@ public class ColQueryStandardTest {
@Test
public void TupleProjection(){
List<Tuple> tuples = MiniApi.from(cat, data).list(new QTuple(cat.name, cat.birthdate));
List<Tuple> tuples = MiniApi.from(cat, data)
.list(new QTuple(cat.name, cat.birthdate));
for (Tuple tuple : tuples){
assertNotNull(tuple.get(cat.name));
assertNotNull(tuple.get(cat.birthdate));
@ -102,7 +103,8 @@ public class ColQueryStandardTest {
@SuppressWarnings("unchecked")
@Test
public void ArrayProjection(){
List<String[]> results = MiniApi.from(cat, data).list(new ArrayConstructorExpression<String>(String[].class, cat.name));
List<String[]> results = MiniApi.from(cat, data)
.list(new ArrayConstructorExpression<String>(String[].class, cat.name));
assertFalse(results.isEmpty());
for (String[] result : results){
assertNotNull(result[0]);
@ -111,7 +113,8 @@ public class ColQueryStandardTest {
@Test
public void ConstructorProjection(){
List<Projection> projections = MiniApi.from(cat, data).list(ConstructorExpression.create(Projection.class, cat.name, cat));
List<Projection> projections = MiniApi.from(cat, data)
.list(ConstructorExpression.create(Projection.class, cat.name, cat));
assertFalse(projections.isEmpty());
for (Projection projection : projections){
assertNotNull(projection);

View File

@ -52,6 +52,11 @@ public class Cat extends Animal {
this.kittensByName = Collections.singletonMap("Kitty", kitten);
this.name = name;
}
public Cat(String name, String kittenName){
this(name);
kittens.get(0).setName(kittenName);
}
@QueryProjection
public Cat(String name, int id) {

View File

@ -0,0 +1,56 @@
package com.mysema.query.collections;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import java.util.List;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
public class CollectionTest {
private final QCat cat = new QCat("cat");
private final QCat other = new QCat("other");
private List<Cat> cats;
@Before
public void setUp(){
Cat cat1 = new Cat("1");
cat1.setKittens(Arrays.asList(cat1));
Cat cat2 = new Cat("2");
cat2.setKittens(Arrays.asList(cat1, cat2));
Cat cat3 = new Cat("3");
cat3.setKittens(Arrays.asList(cat1, cat2, cat3));
Cat cat4 = new Cat("4");
cat4.setKittens(Arrays.asList(cat1, cat2, cat3, cat4));
cats = Arrays.asList(cat1, cat2, cat3, cat4);
}
@Test
public void Join(){
assertEquals("4", MiniApi.from(cat, cats).innerJoin(cat.kittens, other).where(other.name.eq("4")).uniqueResult(cat.name));
}
@Test
public void Any(){
assertEquals("4", MiniApi.from(cat, cats).where(cat.kittens.any().name.eq("4")).uniqueResult(cat.name));
}
@Test
public void Any2(){
assertEquals(4, MiniApi.from(cat, cats).where(cat.kittens.any().name.isNotNull()).count());
}
@Test
@Ignore
public void Any3(){
// TODO : support multiple levels of any usage
assertEquals(4, MiniApi.from(cat, cats).where(cat.kittens.any().name.isNotNull(), cat.kittens.any().kittens.any().isNotNull()).count());
}
}