mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-30 21:08:30 +08:00
Use deterministic path creation
This commit is contained in:
parent
fe4bffff81
commit
b958a2aa9c
@ -48,7 +48,7 @@ public class CollQueryMixin<T> extends QueryMixin<T> {
|
||||
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(),
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -31,7 +31,7 @@ import com.querydsl.core.types.template.BooleanTemplate;
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CollectionAnyVisitor implements Visitor<Expression<?>,Context> {
|
||||
|
||||
public static final CollectionAnyVisitor DEFAULT = new CollectionAnyVisitor();
|
||||
private int replacedCounter;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static <T> Path<T> replaceParent(Path<T> path, Path<?> parent) {
|
||||
@ -110,7 +110,7 @@ public class CollectionAnyVisitor implements Visitor<Expression<?>,Context> {
|
||||
Path<?> parent = (Path<?>) expr.getMetadata().getParent().accept(this, context);
|
||||
expr = new PathImpl<Object>(expr.getType(), PathMetadataFactory.forCollectionAny(parent));
|
||||
EntityPath<?> replacement = new EntityPathBase<Object>(expr.getType(),
|
||||
ExpressionUtils.createRootVariable(expr));
|
||||
ExpressionUtils.createRootVariable(expr, replacedCounter++));
|
||||
context.add(expr, replacement);
|
||||
return replacement;
|
||||
|
||||
@ -135,6 +135,4 @@ public class CollectionAnyVisitor implements Visitor<Expression<?>,Context> {
|
||||
return expr;
|
||||
}
|
||||
|
||||
protected CollectionAnyVisitor() {}
|
||||
|
||||
}
|
||||
|
||||
@ -46,6 +46,8 @@ public class QueryMixin<T> {
|
||||
}
|
||||
};
|
||||
|
||||
protected final CollectionAnyVisitor collectionAnyVisitor = new CollectionAnyVisitor();
|
||||
|
||||
private T self;
|
||||
|
||||
public QueryMixin() {
|
||||
@ -123,7 +125,7 @@ public class QueryMixin<T> {
|
||||
|
||||
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();
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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<Boolean> 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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<T> extends QueryMixin<T> {
|
||||
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);
|
||||
|
||||
@ -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<Object> newParent = new EntityPathBase<Object>(parent.getType(),
|
||||
ExpressionUtils.createRootVariable(parent));
|
||||
ExpressionUtils.createRootVariable(parent, Math.abs(condition.hashCode())));
|
||||
EntityPath<Object> newChild = new EntityPathBase<Object>(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() {}
|
||||
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ class JPAListAccessVisitor extends ReplaceVisitor<Void> {
|
||||
// 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),
|
||||
|
||||
@ -27,7 +27,7 @@ class JPAMapAccessVisitor extends ReplaceVisitor<Void> {
|
||||
ParameterizedExpression map = (ParameterizedExpression<?>) expr.getArg(0);
|
||||
Expression key = expr.getArg(1);
|
||||
Path replacement = new PathImpl<Object>(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<Void> {
|
||||
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),
|
||||
|
||||
@ -49,6 +49,8 @@ public class JPAQueryMixin<T> extends QueryMixin<T> {
|
||||
|
||||
private final JPAListAccessVisitor listAccessVisitor;
|
||||
|
||||
private final JPACollectionAnyVisitor collectionAnyVisitor;
|
||||
|
||||
private final ReplaceVisitor<Void> replaceVisitor = new ReplaceVisitor<Void>() {
|
||||
public Expression<?> visit(Path<?> expr, Void context) {
|
||||
return convertPathForOrder(expr);
|
||||
@ -67,18 +69,21 @@ public class JPAQueryMixin<T> extends QueryMixin<T> {
|
||||
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<T> extends QueryMixin<T> {
|
||||
}
|
||||
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;
|
||||
|
||||
@ -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<Boolean> 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));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user