diff --git a/querydsl-collections/src/main/java/com/querydsl/collections/CollQueryMixin.java b/querydsl-collections/src/main/java/com/querydsl/collections/CollQueryMixin.java index eb2e65ec4..cc5ebd6bd 100644 --- a/querydsl-collections/src/main/java/com/querydsl/collections/CollQueryMixin.java +++ b/querydsl-collections/src/main/java/com/querydsl/collections/CollQueryMixin.java @@ -48,7 +48,7 @@ public class CollQueryMixin extends QueryMixin { predicate = (Predicate)ExpressionUtils.extract(predicate); if (predicate != null) { Context context = new Context(); - Predicate transformed = (Predicate) predicate.accept(CollectionAnyVisitor.DEFAULT, context); + Predicate transformed = (Predicate) predicate.accept(collectionAnyVisitor, context); for (int i = 0; i < context.paths.size(); i++) { leftJoin( (Path)context.paths.get(i).getMetadata().getParent(), diff --git a/querydsl-collections/src/main/java/com/querydsl/collections/DefaultEvaluatorFactory.java b/querydsl-collections/src/main/java/com/querydsl/collections/DefaultEvaluatorFactory.java index 1f92bc898..b8c6f2188 100644 --- a/querydsl-collections/src/main/java/com/querydsl/collections/DefaultEvaluatorFactory.java +++ b/querydsl-collections/src/main/java/com/querydsl/collections/DefaultEvaluatorFactory.java @@ -14,10 +14,7 @@ package com.querydsl.collections; import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import javax.annotation.Nullable; import javax.tools.JavaCompiler; @@ -57,6 +54,8 @@ public class DefaultEvaluatorFactory { private final CollQueryTemplates templates; + private final CollectionAnyVisitor collectionAnyVisitor = new CollectionAnyVisitor(); + public DefaultEvaluatorFactory(CollQueryTemplates templates) { this(templates, Thread.currentThread().getContextClassLoader()); @@ -215,7 +214,7 @@ public class DefaultEvaluatorFactory { if (colAnyJoin) { Context context = new Context(); Expression replacement = alias.getArg(0) - .accept(CollectionAnyVisitor.DEFAULT, context); + .accept(collectionAnyVisitor, context); ser.handle(replacement); } else { ser.handle(alias.getArg(0)); diff --git a/querydsl-core/src/main/java/com/querydsl/core/support/CollectionAnyVisitor.java b/querydsl-core/src/main/java/com/querydsl/core/support/CollectionAnyVisitor.java index 441a1b96b..18320e7e3 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/support/CollectionAnyVisitor.java +++ b/querydsl-core/src/main/java/com/querydsl/core/support/CollectionAnyVisitor.java @@ -31,7 +31,7 @@ import com.querydsl.core.types.template.BooleanTemplate; @SuppressWarnings("unchecked") public class CollectionAnyVisitor implements Visitor,Context> { - public static final CollectionAnyVisitor DEFAULT = new CollectionAnyVisitor(); + private int replacedCounter; @SuppressWarnings("rawtypes") private static Path replaceParent(Path path, Path parent) { @@ -110,7 +110,7 @@ public class CollectionAnyVisitor implements Visitor,Context> { Path parent = (Path) expr.getMetadata().getParent().accept(this, context); expr = new PathImpl(expr.getType(), PathMetadataFactory.forCollectionAny(parent)); EntityPath replacement = new EntityPathBase(expr.getType(), - ExpressionUtils.createRootVariable(expr)); + ExpressionUtils.createRootVariable(expr, replacedCounter++)); context.add(expr, replacement); return replacement; @@ -135,6 +135,4 @@ public class CollectionAnyVisitor implements Visitor,Context> { return expr; } - protected CollectionAnyVisitor() {} - } diff --git a/querydsl-core/src/main/java/com/querydsl/core/support/QueryMixin.java b/querydsl-core/src/main/java/com/querydsl/core/support/QueryMixin.java index e9442392c..69ea042c9 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/support/QueryMixin.java +++ b/querydsl-core/src/main/java/com/querydsl/core/support/QueryMixin.java @@ -46,6 +46,8 @@ public class QueryMixin { } }; + protected final CollectionAnyVisitor collectionAnyVisitor = new CollectionAnyVisitor(); + private T self; public QueryMixin() { @@ -123,7 +125,7 @@ public class QueryMixin { private Path normalizePath(Path expr) { Context context = new Context(); - Path replaced = (Path)expr.accept(CollectionAnyVisitor.DEFAULT, context); + Path replaced = (Path)expr.accept(collectionAnyVisitor, context); if (!replaced.equals(expr)) { for (int i = 0; i < context.paths.size(); i++) { Path path = context.paths.get(i).getMetadata().getParent(); diff --git a/querydsl-core/src/main/java/com/querydsl/core/types/ExpressionUtils.java b/querydsl-core/src/main/java/com/querydsl/core/types/ExpressionUtils.java index 39b8b2d95..07fce7808 100644 --- a/querydsl-core/src/main/java/com/querydsl/core/types/ExpressionUtils.java +++ b/querydsl-core/src/main/java/com/querydsl/core/types/ExpressionUtils.java @@ -13,10 +13,10 @@ */ package com.querydsl.core.types; -import javax.annotation.Nullable; - import java.util.*; +import javax.annotation.Nullable; + import com.google.common.collect.ImmutableList; import com.querydsl.core.BooleanBuilder; import com.querydsl.core.QueryException; @@ -533,14 +533,14 @@ public final class ExpressionUtils { } /** - * Create a new root variable based on the given path + * Create a new root variable based on the given path and suffix * * @param path + * @param suffix * @return */ - public static String createRootVariable(Path path) { - String variable = path.accept(ToStringVisitor.DEFAULT, TEMPLATES).replace('.', '_'); - String suffix = UUID.randomUUID().toString().replace("-", "").substring(0, 5); + public static String createRootVariable(Path path, int suffix) { + String variable = path.accept(ToStringVisitor.DEFAULT, TEMPLATES); return variable + "_" + suffix; } diff --git a/querydsl-core/src/test/java/com/querydsl/core/support/CollectionAnyVisitorTest.java b/querydsl-core/src/test/java/com/querydsl/core/support/CollectionAnyVisitorTest.java index 48ca5ede7..6436f3850 100644 --- a/querydsl-core/src/test/java/com/querydsl/core/support/CollectionAnyVisitorTest.java +++ b/querydsl-core/src/test/java/com/querydsl/core/support/CollectionAnyVisitorTest.java @@ -30,56 +30,58 @@ public class CollectionAnyVisitorTest { @Test public void Path() { - assertMatches("cat_kittens.*", serialize(cat.kittens.any())); + assertEquals("cat_kittens_0", serialize(cat.kittens.any())); } @Test public void Longer_Path() { - assertMatches("cat_kittens.*\\.name", serialize(cat.kittens.any().name)); + assertEquals("cat_kittens_0.name", serialize(cat.kittens.any().name)); + } + + @Test + public void Longer_Path2() { + CollectionAnyVisitor visitor = new CollectionAnyVisitor(); + assertEquals("cat_kittens_0.name", serialize(cat.kittens.any().name, visitor)); + assertEquals("cat_kittens_1.name", serialize(cat.kittens.any().name, visitor)); } @Test public void Very_Long_Path() { - assertMatches("cat_kittens.*_kittens.*\\.name", serialize(cat.kittens.any().kittens.any().name)); + assertEquals("cat_kittens_0_kittens_1.name", serialize(cat.kittens.any().kittens.any().name)); } @Test public void Simple_BooleanOperation() { - Predicate predicate = cat.kittens.any().name.eq("Ruth123"); - assertMatches("cat_kittens.*\\.name = Ruth123", serialize(predicate)); + Predicate predicate = cat.kittens.any().name.eq("Ruth123"); + assertEquals("cat_kittens_0.name = Ruth123", serialize(predicate)); } @Test public void Simple_StringOperation() { - Predicate predicate = cat.kittens.any().name.substring(1).eq("uth123"); - assertMatches("substring\\(cat_kittens.*\\.name,1\\) = uth123", serialize(predicate)); + Predicate predicate = cat.kittens.any().name.substring(1).eq("uth123"); + assertEquals("substring(cat_kittens_0.name,1) = uth123", serialize(predicate)); } @Test public void And_Operation() { Predicate predicate = cat.kittens.any().name.eq("Ruth123").and(cat.kittens.any().bodyWeight.gt(10.0)); - assertMatches("cat_kittens.*\\.name = Ruth123 && cat_kittens.*\\.bodyWeight > 10.0", serialize(predicate)); + assertEquals("cat_kittens_0.name = Ruth123 && cat_kittens_1.bodyWeight > 10.0", serialize(predicate)); } @Test public void Template() { Expression templateExpr = TemplateExpressionImpl.create(Boolean.class, "{0} = {1}", cat.kittens.any().name, ConstantImpl.create("Ruth123")); - assertMatches("cat_kittens.*\\.name = Ruth123", serialize(templateExpr)); + assertEquals("cat_kittens_0.name = Ruth123", serialize(templateExpr)); } private String serialize(Expression expression) { - CollectionAnyVisitor visitor = new CollectionAnyVisitor() { - @Override - protected Predicate exists(Context c, Predicate condition) { - return condition; - } - }; + return serialize(expression, new CollectionAnyVisitor()); + } + + private String serialize(Expression expression, CollectionAnyVisitor visitor) { Expression transformed = expression.accept(visitor, new Context()); return transformed.toString(); } - - private static void assertMatches(String str1, String str2) { - assertTrue(str2, str2.matches(str1)); - } + } diff --git a/querydsl-jdo/src/main/java/com/querydsl/jdo/JDOQueryMixin.java b/querydsl-jdo/src/main/java/com/querydsl/jdo/JDOQueryMixin.java index 0163ed41f..9be5179eb 100644 --- a/querydsl-jdo/src/main/java/com/querydsl/jdo/JDOQueryMixin.java +++ b/querydsl-jdo/src/main/java/com/querydsl/jdo/JDOQueryMixin.java @@ -14,15 +14,9 @@ package com.querydsl.jdo; import com.querydsl.core.QueryMetadata; -import com.querydsl.core.support.CollectionAnyVisitor; import com.querydsl.core.support.Context; import com.querydsl.core.support.QueryMixin; -import com.querydsl.core.types.EntityPath; -import com.querydsl.core.types.ExpressionUtils; -import com.querydsl.core.types.Ops; -import com.querydsl.core.types.Path; -import com.querydsl.core.types.Predicate; -import com.querydsl.core.types.PredicateOperation; +import com.querydsl.core.types.*; /** * JDOQueryMixin extends {@link QueryMixin} to provide module specific extensions @@ -48,7 +42,7 @@ public class JDOQueryMixin extends QueryMixin { predicate = (Predicate)ExpressionUtils.extract(predicate); if (predicate != null) { Context context = new Context(); - Predicate transformed = (Predicate) predicate.accept(CollectionAnyVisitor.DEFAULT, context); + Predicate transformed = (Predicate) predicate.accept(collectionAnyVisitor, context); for (int i = 0; i < context.paths.size(); i++) { Path path = context.paths.get(i); addCondition(context, i, path, role); diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPACollectionAnyVisitor.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPACollectionAnyVisitor.java index c81cdd253..86fe241c5 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPACollectionAnyVisitor.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPACollectionAnyVisitor.java @@ -31,8 +31,6 @@ import com.querydsl.core.types.path.SimplePath; */ public final class JPACollectionAnyVisitor extends CollectionAnyVisitor { - public static final JPACollectionAnyVisitor DEFAULT = new JPACollectionAnyVisitor(); - @SuppressWarnings("unchecked") @Override protected Predicate exists(Context c, Predicate condition) { @@ -46,7 +44,7 @@ public final class JPACollectionAnyVisitor extends CollectionAnyVisitor { // join via parent Path parent = child.getMetadata().getParent(); EntityPathBase newParent = new EntityPathBase(parent.getType(), - ExpressionUtils.createRootVariable(parent)); + ExpressionUtils.createRootVariable(parent, Math.abs(condition.hashCode()))); EntityPath newChild = new EntityPathBase(child.getType(), PathMetadataFactory.forProperty(newParent, child.getMetadata().getName())); query.from(newParent).innerJoin(newChild, replacement); @@ -58,6 +56,4 @@ public final class JPACollectionAnyVisitor extends CollectionAnyVisitor { return query.exists(); } - private JPACollectionAnyVisitor() {} - } diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAListAccessVisitor.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAListAccessVisitor.java index 6c1837d55..dca8ef52d 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAListAccessVisitor.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAListAccessVisitor.java @@ -31,7 +31,7 @@ class JPAListAccessVisitor extends ReplaceVisitor { // join parent as path123 on index(path123) = ... Path parent = pathMetadata.getParent(); replacement = new PathImpl(expr.getType(), - ExpressionUtils.createRootVariable(parent)); + ExpressionUtils.createRootVariable(parent, replacements.size())); metadata.addJoin(JoinType.LEFTJOIN, ExpressionUtils.as(parent, replacement)); metadata.addJoinCondition(ExpressionUtils.eq( (Expression)Expressions.operation(Integer.class, JPQLOps.INDEX, replacement), diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAMapAccessVisitor.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAMapAccessVisitor.java index 4d92a9ec2..5150d2ec3 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAMapAccessVisitor.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAMapAccessVisitor.java @@ -27,7 +27,7 @@ class JPAMapAccessVisitor extends ReplaceVisitor { ParameterizedExpression map = (ParameterizedExpression) expr.getArg(0); Expression key = expr.getArg(1); Path replacement = new PathImpl(map.getParameter(1), - ExpressionUtils.createRootVariable((Path)map)); + ExpressionUtils.createRootVariable((Path)map, Math.abs(expr.hashCode()))); metadata.addJoin(JoinType.LEFTJOIN, ExpressionUtils.as(map, replacement)); metadata.addJoinCondition(ExpressionUtils.eq( Expressions.operation(map.getParameter(0), JPQLOps.KEY, replacement), @@ -54,7 +54,7 @@ class JPAMapAccessVisitor extends ReplaceVisitor { Path parent = pathMetadata.getParent(); ParameterizedExpression parExpr = (ParameterizedExpression) parent; replacement = new PathImpl(parExpr.getParameter(1), - ExpressionUtils.createRootVariable(parent)); + ExpressionUtils.createRootVariable(parent, replacements.size())); metadata.addJoin(JoinType.LEFTJOIN, ExpressionUtils.as(parent, replacement)); metadata.addJoinCondition(ExpressionUtils.eq( Expressions.operation(parExpr.getParameter(0), JPQLOps.KEY, replacement), diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAQueryMixin.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAQueryMixin.java index 38483ced9..04d901f1b 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAQueryMixin.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPAQueryMixin.java @@ -49,6 +49,8 @@ public class JPAQueryMixin extends QueryMixin { private final JPAListAccessVisitor listAccessVisitor; + private final JPACollectionAnyVisitor collectionAnyVisitor; + private final ReplaceVisitor replaceVisitor = new ReplaceVisitor() { public Expression visit(Path expr, Void context) { return convertPathForOrder(expr); @@ -67,18 +69,21 @@ public class JPAQueryMixin extends QueryMixin { public JPAQueryMixin() { mapAccessVisitor = new JPAMapAccessVisitor(getMetadata()); listAccessVisitor = new JPAListAccessVisitor(getMetadata()); + collectionAnyVisitor = new JPACollectionAnyVisitor(); } public JPAQueryMixin(QueryMetadata metadata) { super(metadata); mapAccessVisitor = new JPAMapAccessVisitor(metadata); listAccessVisitor = new JPAListAccessVisitor(metadata); + collectionAnyVisitor = new JPACollectionAnyVisitor(); } public JPAQueryMixin(T self, QueryMetadata metadata) { super(self, metadata); mapAccessVisitor = new JPAMapAccessVisitor(metadata); listAccessVisitor = new JPAListAccessVisitor(metadata); + collectionAnyVisitor = new JPACollectionAnyVisitor(); } public T fetch() { @@ -196,7 +201,7 @@ public class JPAQueryMixin extends QueryMixin { } if (predicate != null) { // transform any usage - predicate = (Predicate) predicate.accept(JPACollectionAnyVisitor.DEFAULT, new Context()); + predicate = (Predicate) predicate.accept(collectionAnyVisitor, new Context()); return predicate; } else { return null; diff --git a/querydsl-jpa/src/test/java/com/querydsl/jpa/JPACollectionAnyVisitorTest.java b/querydsl-jpa/src/test/java/com/querydsl/jpa/JPACollectionAnyVisitorTest.java index 47284936f..171bb0845 100644 --- a/querydsl-jpa/src/test/java/com/querydsl/jpa/JPACollectionAnyVisitorTest.java +++ b/querydsl-jpa/src/test/java/com/querydsl/jpa/JPACollectionAnyVisitorTest.java @@ -13,7 +13,7 @@ */ package com.querydsl.jpa; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -22,7 +22,6 @@ import com.querydsl.core.types.ConstantImpl; import com.querydsl.core.types.Expression; import com.querydsl.core.types.Predicate; import com.querydsl.core.types.TemplateExpressionImpl; -import com.querydsl.jpa.domain.JobFunction; import com.querydsl.jpa.domain.QCat; import com.querydsl.jpa.domain.QDomesticCat; import com.querydsl.jpa.domain.QEmployee; @@ -34,57 +33,57 @@ public class JPACollectionAnyVisitorTest { @Test public void Path() { - assertMatches("cat_kittens.*", serialize(cat.kittens.any())); + assertEquals("cat_kittens_0", serialize(cat.kittens.any())); } @Test public void Longer_Path() { - assertMatches("cat_kittens.*\\.name", serialize(cat.kittens.any().name)); + assertEquals("cat_kittens_0.name", serialize(cat.kittens.any().name)); } @Test public void Simple_BooleanOperation() { Predicate predicate = cat.kittens.any().name.eq("Ruth123"); - assertMatches("exists \\(select 1\n" + - "from cat.kittens as cat_kittens.*\n" + - "where cat_kittens.*\\.name = \\?1\\)", serialize(predicate)); + assertEquals("exists (select 1\n" + + "from cat.kittens as cat_kittens_0\n" + + "where cat_kittens_0.name = ?1)", serialize(predicate)); } @Test public void Simple_BooleanOperation_ElementCollection() { QEmployee employee = QEmployee.employee; - Predicate predicate = employee.jobFunctions.any().eq(JobFunction.CODER); - assertMatches("exists \\(select 1\n" + - "from Employee employee.*\n" + - " inner join employee.*.jobFunctions as employee_jobFunctions.*\n" + - "where employee.* = employee and employee_jobFunctions.* = \\?1\\)", serialize(predicate)); + Predicate predicate = employee.jobFunctions.any().stringValue().eq("CODER"); + assertEquals("exists (select 1\n" + + "from Employee employee_1463394548\n" + + " inner join employee_1463394548.jobFunctions as employee_jobFunctions_0\n" + + "where employee_1463394548 = employee and str(employee_jobFunctions_0) = ?1)", serialize(predicate)); } @Test public void Simple_StringOperation() { Predicate predicate = cat.kittens.any().name.substring(1).eq("uth123"); - assertMatches("exists \\(select 1\n"+ - "from cat.kittens as cat_kittens.*\n" + - "where substring\\(cat_kittens.*\\.name,2\\) = \\?1\\)", serialize(predicate)); + assertEquals("exists (select 1\n" + + "from cat.kittens as cat_kittens_0\n" + + "where substring(cat_kittens_0.name,2) = ?1)", serialize(predicate)); } @Test public void And_Operation() { Predicate predicate = cat.kittens.any().name.eq("Ruth123").and(cat.kittens.any().bodyWeight.gt(10.0)); - assertMatches("exists \\(select 1\n"+ - "from cat.kittens as cat_kittens.*\n" + - "where cat_kittens.*\\.name = \\?1\\) and exists \\(select 1\n" + - "from cat.kittens as cat_kittens.*\n" + - "where cat_kittens.*\\.bodyWeight > \\?2\\)", serialize(predicate)); + assertEquals("exists (select 1\n" + + "from cat.kittens as cat_kittens_0\n" + + "where cat_kittens_0.name = ?1) and exists (select 1\n" + + "from cat.kittens as cat_kittens_1\n" + + "where cat_kittens_1.bodyWeight > ?2)", serialize(predicate)); } @Test public void Template() { Expression templateExpr = TemplateExpressionImpl.create(Boolean.class, "{0} = {1}", cat.kittens.any().name, ConstantImpl.create("Ruth123")); - assertMatches("exists \\(select 1\n" + - "from cat.kittens as cat_kittens.*\n" + - "where cat_kittens.*\\.name = \\?1\\)", serialize(templateExpr)); + assertEquals("exists (select 1\n" + + "from cat.kittens as cat_kittens_0\n" + + "where cat_kittens_0.name = ?1)", serialize(templateExpr)); } @Test @@ -97,19 +96,16 @@ public class JPACollectionAnyVisitorTest { QDomesticCat anyCat = QCat.cat.kittens.any().as(QDomesticCat.class); Predicate predicate = anyCat.name.eq("X"); - assertMatches("exists \\(select 1\n" + - "from cat.kittens as cat_kittens.*\n" + - "where cat_kittens.*\\.name = \\?1\\)", serialize(predicate)); + assertEquals("exists (select 1\n" + + "from cat.kittens as cat_kittens_0\n" + + "where cat_kittens_0.name = ?1)", serialize(predicate)); } private String serialize(Expression expression) { - Expression transformed = expression.accept(JPACollectionAnyVisitor.DEFAULT, new Context()); + Expression transformed = expression.accept(new JPACollectionAnyVisitor(), new Context()); JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT, null); serializer.handle(transformed); return serializer.toString(); } - private static void assertMatches(String str1, String str2) { - assertTrue(str2, str2.matches(str1)); - } }