diff --git a/querydsl-core/src/main/java/com/mysema/query/support/CollectionAnyVisitor.java b/querydsl-core/src/main/java/com/mysema/query/support/CollectionAnyVisitor.java index b7a9e2fe2..82a55a93d 100644 --- a/querydsl-core/src/main/java/com/mysema/query/support/CollectionAnyVisitor.java +++ b/querydsl-core/src/main/java/com/mysema/query/support/CollectionAnyVisitor.java @@ -14,6 +14,8 @@ package com.mysema.query.support; +import java.util.UUID; + import com.mysema.query.types.Constant; import com.mysema.query.types.EntityPath; import com.mysema.query.types.Expression; @@ -118,9 +120,10 @@ public class CollectionAnyVisitor implements Visitor,Context>{ @SuppressWarnings("unchecked") @Override public Expression visit(Path expr, Context context) { - if (expr.getMetadata().getPathType() == PathType.COLLECTION_ANY){ + if (expr.getMetadata().getPathType() == PathType.COLLECTION_ANY){ String variable = expr.accept(ToStringVisitor.DEFAULT, TEMPLATE).replace('.', '_'); - EntityPath replacement = new EntityPathBase(expr.getType(), variable); + String suffix = UUID.randomUUID().toString().replace("-", "").substring(0,5); + EntityPath replacement = new EntityPathBase(expr.getType(), variable + suffix); context.add(expr, replacement); return replacement; @@ -134,7 +137,7 @@ public class CollectionAnyVisitor implements Visitor,Context>{ } return expr; } - + @Override public Expression visit(SubQueryExpression expr, Context context) { return expr; diff --git a/querydsl-core/src/main/java/com/mysema/query/support/SerializerBase.java b/querydsl-core/src/main/java/com/mysema/query/support/SerializerBase.java index 9def1a9fc..ebc1fcda9 100644 --- a/querydsl-core/src/main/java/com/mysema/query/support/SerializerBase.java +++ b/querydsl-core/src/main/java/com/mysema/query/support/SerializerBase.java @@ -59,6 +59,10 @@ public abstract class SerializerBase> implements Vis private static final Pattern OPERATION = Pattern.compile(NUMBER + WS + "[\\+\\-]" + WS + NUMBER); + private static final Pattern ADDITION = Pattern.compile(NUMBER + WS + "\\+" + WS + NUMBER); + + //private static final Pattern SUBTRACTION = Pattern.compile(NUMBER + WS + "\\-" + WS + NUMBER); + private String constantPrefix = "a"; private String paramPrefix = "p"; @@ -85,13 +89,13 @@ public abstract class SerializerBase> implements Vis rv.append(queryString.subSequence(end, m.start())); } String str = queryString.substring(m.start(), m.end()); + boolean addition = ADDITION.matcher(str).matches(); String[] operands = OPERATOR.split(str); - char operator = str.charAt(operands[0].length()); BigDecimal result = null; - if (operator == '+') { + if (addition) { result = new BigDecimal(operands[0]).add(new BigDecimal(operands[1])); } else { - result = new BigDecimal(operands[0]).add(new BigDecimal(operands[1])); + result = new BigDecimal(operands[0]).subtract(new BigDecimal(operands[1])); } rv.append(result.toString()); end = m.end(); diff --git a/querydsl-core/src/test/java/com/mysema/query/support/CollectionAnyVisitorTest.java b/querydsl-core/src/test/java/com/mysema/query/support/CollectionAnyVisitorTest.java index ff5d236a3..d4b3f7d22 100644 --- a/querydsl-core/src/test/java/com/mysema/query/support/CollectionAnyVisitorTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/support/CollectionAnyVisitorTest.java @@ -13,7 +13,7 @@ */ package com.mysema.query.support; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import org.junit.Test; @@ -27,46 +27,46 @@ import com.mysema.query.types.TemplateExpressionImpl; public class CollectionAnyVisitorTest { private QCat cat = QCat.cat; - + @Test public void Path(){ - assertEquals("cat_kittens", serialize(cat.kittens.any())); + assertMatches("cat_kittens.*", serialize(cat.kittens.any())); } @Test public void Longer_Path(){ - assertEquals("cat_kittens.name", serialize(cat.kittens.any().name)); + assertMatches("cat_kittens.*\\.name", serialize(cat.kittens.any().name)); } @Test public void Very_Long_Path(){ - assertEquals("cat_kittens_kittens.name", serialize(cat.kittens.any().kittens.any().name)); + assertMatches("cat_kittens_kittens.*\\.name", serialize(cat.kittens.any().kittens.any().name)); } @Test public void Simple_BooleanOperation(){ Predicate predicate = cat.kittens.any().name.eq("Ruth123"); - assertEquals("cat_kittens.name = Ruth123", serialize(predicate)); + assertMatches("cat_kittens.*\\.name = Ruth123", serialize(predicate)); } @Test public void Simple_StringOperation(){ Predicate predicate = cat.kittens.any().name.substring(1).eq("uth123"); - assertEquals("substring(cat_kittens.name,1) = uth123", serialize(predicate)); + assertMatches("substring\\(cat_kittens.*\\.name,1\\) = uth123", serialize(predicate)); } @Test public void And_Operation(){ // TODO : the subqueries should be merged Predicate predicate = cat.kittens.any().name.eq("Ruth123").and(cat.kittens.any().bodyWeight.gt(10.0)); - assertEquals("cat_kittens.name = Ruth123 && cat_kittens.bodyWeight > 10.0", serialize(predicate)); + assertMatches("cat_kittens.*\\.name = Ruth123 && cat_kittens.*\\.bodyWeight > 10.0", serialize(predicate)); } @Test public void Template(){ Expression templateExpr = TemplateExpressionImpl.create(Boolean.class, "{0} = {1}", cat.kittens.any().name, ConstantImpl.create("Ruth123")); - assertEquals("cat_kittens.name = Ruth123", serialize(templateExpr)); + assertMatches("cat_kittens.*\\.name = Ruth123", serialize(templateExpr)); } private String serialize(Expression expression){ @@ -80,4 +80,7 @@ public class CollectionAnyVisitorTest { return transformed.toString(); } + private static void assertMatches(String str1, String str2) { + assertTrue(str2, str2.matches(str1)); + } } diff --git a/querydsl-core/src/test/java/com/mysema/query/support/SerializerBaseTest.java b/querydsl-core/src/test/java/com/mysema/query/support/SerializerBaseTest.java index 2fd6dcb40..6cfcbef97 100644 --- a/querydsl-core/src/test/java/com/mysema/query/support/SerializerBaseTest.java +++ b/querydsl-core/src/test/java/com/mysema/query/support/SerializerBaseTest.java @@ -7,11 +7,19 @@ import org.junit.Test; public class SerializerBaseTest { @Test - public void Normalize() { + public void Normalize_Addition() { assertEquals("3", SerializerBase.normalize("1+2")); assertEquals("where 3 = 3", SerializerBase.normalize("where 1+2 = 3")); assertEquals("where 3.3 = 3.3", SerializerBase.normalize("where 1.1+2.2 = 3.3")); assertEquals("where 3.3 = 3.3", SerializerBase.normalize("where 1.1 + 2.2 = 3.3")); } + + @Test + public void Normalize_Subtraction() { + assertEquals("3", SerializerBase.normalize("5-2")); + assertEquals("where 3 = 3", SerializerBase.normalize("where 5-2 = 3")); + assertEquals("where 3.3 = 3.3", SerializerBase.normalize("where 5.5-2.2 = 3.3")); + assertEquals("where 3.3 = 3.3", SerializerBase.normalize("where 5.5 - 2.2 = 3.3")); + } } diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLCollectionAnyVisitor.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLCollectionAnyVisitor.java index 9b4ce71ca..6cacc9ec5 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLCollectionAnyVisitor.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLCollectionAnyVisitor.java @@ -23,7 +23,7 @@ import com.mysema.query.types.PredicateOperation; * @author tiwe * */ -public final class JPQLCollectionAnyVisitor extends CollectionAnyVisitor{ +public final class JPQLCollectionAnyVisitor extends CollectionAnyVisitor { public static final JPQLCollectionAnyVisitor DEFAULT = new JPQLCollectionAnyVisitor(); diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLSerializer.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLSerializer.java index 53ffa85b0..b8ef2f718 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLSerializer.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLSerializer.java @@ -330,17 +330,6 @@ public class JPQLSerializer extends SerializerBase { } return null; } - - @SuppressWarnings("rawtypes") - private SingularAttribute getIdProperty(EntityType entity) { - Set singularAttributes = entity.getSingularAttributes(); - for (SingularAttribute singularAttribute : singularAttributes) { - if (singularAttribute.isId()){ - return singularAttribute; - } - } - return null; - } @Override @SuppressWarnings("unchecked") @@ -348,7 +337,6 @@ public class JPQLSerializer extends SerializerBase { boolean old = wrapElements; wrapElements = templates.wrapElements(operator); - // TODO : refactor each case into own method if (operator.equals(Ops.IN)) { if (args.get(1) instanceof Path) { visitAnyInPath(type, args); @@ -359,24 +347,10 @@ public class JPQLSerializer extends SerializerBase { } } else if (operator.equals(Ops.INSTANCE_OF)) { - if (templates.isTypeAsString()) { - List> newArgs = new ArrayList>(args); - Class cl = ((Class) ((Constant) newArgs.get(1)).getConstant()); - // use discriminator value instead of fqnm - if (cl.getAnnotation(DiscriminatorValue.class) != null) { - newArgs.set(1, ConstantImpl.create(cl.getAnnotation(DiscriminatorValue.class).value())); - } else { - newArgs.set(1, ConstantImpl.create(cl.getName())); - } - super.visitOperation(type, operator, newArgs); - } else { - super.visitOperation(type, operator, args); - } + visitInstanceOf(type, operator, args); } else if (operator.equals(Ops.NUMCAST)) { - Class targetType = (Class) ((Constant) args.get(1)).getConstant(); - String typeName = targetType.getSimpleName().toLowerCase(Locale.ENGLISH); - visitOperation(targetType, JPQLTemplates.CAST, Arrays.>asList(args.get(0), ConstantImpl.create(typeName))); + visitNumCast(args); } else if (operator.equals(Ops.EXISTS) && args.get(0) instanceof SubQueryExpression) { SubQueryExpression subQuery = (SubQueryExpression) args.get(0); @@ -398,6 +372,29 @@ public class JPQLSerializer extends SerializerBase { wrapElements = old; } + private void visitNumCast(List> args) { + Class targetType = (Class) ((Constant) args.get(1)).getConstant(); + String typeName = targetType.getSimpleName().toLowerCase(Locale.ENGLISH); + visitOperation(targetType, JPQLTemplates.CAST, Arrays.>asList(args.get(0), ConstantImpl.create(typeName))); + } + + private void visitInstanceOf(Class type, Operator operator, + List> args) { + if (templates.isTypeAsString()) { + List> newArgs = new ArrayList>(args); + Class cl = ((Class) ((Constant) newArgs.get(1)).getConstant()); + // use discriminator value instead of fqnm + if (cl.getAnnotation(DiscriminatorValue.class) != null) { + newArgs.set(1, ConstantImpl.create(cl.getAnnotation(DiscriminatorValue.class).value())); + } else { + newArgs.set(1, ConstantImpl.create(cl.getName())); + } + super.visitOperation(type, operator, newArgs); + } else { + super.visitOperation(type, operator, args); + } + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void visitPathInCollection(Class type, Operator operator, List> args) { @@ -410,7 +407,9 @@ public class JPQLSerializer extends SerializerBase { EntityType entityType = metamodel.entity(args.get(0).getType()); if (entityType.hasSingleIdAttribute()) { SingularAttribute id = getIdProperty(entityType); + // turn lhs into id path lhs = new PathImpl(id.getJavaType(), lhs, id.getName()); + // turn rhs into id collection Set ids = new HashSet(); for (Object entity : (Collection)rhs.getConstant()) { ids.add(util.getIdentifier(entity)); @@ -422,6 +421,17 @@ public class JPQLSerializer extends SerializerBase { super.visitOperation(type, operator, args); } + @SuppressWarnings("rawtypes") + private SingularAttribute getIdProperty(EntityType entity) { + Set singularAttributes = entity.getSingularAttributes(); + for (SingularAttribute singularAttribute : singularAttributes) { + if (singularAttribute.isId()){ + return singularAttribute; + } + } + return null; + } + @SuppressWarnings({ "rawtypes", "unchecked" }) private void visitAnyInPath(Class type, List> args) { if (!templates.isEnumInPathSupported() && args.get(0) instanceof Constant && Enum.class.isAssignableFrom(args.get(0).getType())) { diff --git a/querydsl-jpa/src/test/java/com/mysema/query/AbstractStandardTest.java b/querydsl-jpa/src/test/java/com/mysema/query/AbstractStandardTest.java index 797bbc3c3..d82a17bfc 100644 --- a/querydsl-jpa/src/test/java/com/mysema/query/AbstractStandardTest.java +++ b/querydsl-jpa/src/test/java/com/mysema/query/AbstractStandardTest.java @@ -714,6 +714,13 @@ public abstract class AbstractStandardTest { query().from(cat).where(sum(cat.kittens.size()).gt(0)).list(cat); } + @Test + public void Substring() { + for (String str : query().from(cat).list(cat.name.substring(1,2))) { + assertEquals(1, str.length()); + } + } + @Test public void SubQuery(){ QShow show = QShow.show; diff --git a/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPAIntegrationTest.java b/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPAIntegrationTest.java index 79f5325a8..15e01d10d 100644 --- a/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPAIntegrationTest.java +++ b/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPAIntegrationTest.java @@ -36,7 +36,7 @@ import com.mysema.testutil.JPATestRunner; @JPAConfig("hsqldb") public class JPAIntegrationTest extends ParsingTest { - private EntityManager entityManager; + private EntityManager em; @Override protected QueryHelper query() { @@ -47,7 +47,7 @@ public class JPAIntegrationTest extends ParsingTest { System.out.println("query : " + toString().replace('\n', ' ')); // create Query and execute it - Query query = entityManager.createQuery(toString()); + Query query = em.createQuery(toString()); JPAUtil.setConstants(query, getConstants(),getMetadata().getParams()); try { query.getResultList(); @@ -86,8 +86,8 @@ public class JPAIntegrationTest extends ParsingTest { // NOTE : commented out, because HQLSDB doesn't support these queries } - public void setEntityManager(EntityManager entityManager) { - this.entityManager = entityManager; + public void setEntityManager(EntityManager em) { + this.em = em; } } diff --git a/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPQLCollectionAnyVisitorTest.java b/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPQLCollectionAnyVisitorTest.java index c3d4a9a36..f30fe72c6 100644 --- a/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPQLCollectionAnyVisitorTest.java +++ b/querydsl-jpa/src/test/java/com/mysema/query/jpa/JPQLCollectionAnyVisitorTest.java @@ -13,7 +13,7 @@ */ package com.mysema.query.jpa; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import org.junit.Test; @@ -31,48 +31,47 @@ public class JPQLCollectionAnyVisitorTest { @Test public void Path(){ - assertEquals("cat_kittens", serialize(cat.kittens.any())); + assertMatches("cat_kittens.*", serialize(cat.kittens.any())); } @Test public void Longer_Path(){ - assertEquals("cat_kittens.name", serialize(cat.kittens.any().name)); + assertMatches("cat_kittens.*\\.name", serialize(cat.kittens.any().name)); } @Test public void Simple_BooleanOperation(){ Predicate predicate = cat.kittens.any().name.eq("Ruth123"); - assertEquals("exists (select 1\n" + - "from Cat cat_kittens\n" + - "where cat_kittens in elements(cat.kittens) and cat_kittens.name = ?1)", serialize(predicate)); + assertMatches("exists \\(select 1\n" + + "from Cat cat_kittens.*\n" + + "where cat_kittens.* in elements\\(cat\\.kittens\\) and cat_kittens.*\\.name = \\?1\\)", serialize(predicate)); } @Test public void Simple_StringOperation(){ Predicate predicate = cat.kittens.any().name.substring(1).eq("uth123"); - assertEquals("exists (select 1\n" + - "from Cat cat_kittens\n" + - "where cat_kittens in elements(cat.kittens) and substring(cat_kittens.name,2) = ?1)", serialize(predicate)); + assertMatches("exists \\(select 1\n" + + "from Cat cat_kittens.*\n" + + "where cat_kittens.* in elements\\(cat.kittens\\) and substring\\(cat_kittens.*\\.name,2\\) = \\?1\\)", serialize(predicate)); } @Test public void And_Operation(){ - // TODO : the subqueries should be merged Predicate predicate = cat.kittens.any().name.eq("Ruth123").and(cat.kittens.any().bodyWeight.gt(10.0)); - assertEquals("exists (select 1\n" + - "from Cat cat_kittens\n" + - "where cat_kittens in elements(cat.kittens) and cat_kittens.name = ?1) and exists (select 1\n" + - "from Cat cat_kittens\n" + - "where cat_kittens in elements(cat.kittens) and cat_kittens.bodyWeight > ?2)", serialize(predicate)); + assertMatches("exists \\(select 1\n" + + "from Cat cat_kittens.*\n" + + "where cat_kittens.* in elements\\(cat.kittens\\) and cat_kittens.*\\.name = \\?1\\) and exists \\(select 1\n" + + "from Cat cat_kittens.*\n" + + "where cat_kittens.* in elements\\(cat.kittens\\) and cat_kittens.*\\.bodyWeight > \\?2\\)", serialize(predicate)); } @Test public void Template(){ Expression templateExpr = TemplateExpressionImpl.create(Boolean.class, "{0} = {1}", cat.kittens.any().name, ConstantImpl.create("Ruth123")); - assertEquals("exists (select 1\n" + - "from Cat cat_kittens\n" + - "where cat_kittens in elements(cat.kittens) and cat_kittens.name = ?1)", serialize(templateExpr)); + assertMatches("exists \\(select 1\n" + + "from Cat cat_kittens.*\n" + + "where cat_kittens.* in elements\\(cat\\.kittens\\) and cat_kittens.*\\.name = \\?1\\)", serialize(templateExpr)); } private String serialize(Expression expression){ @@ -82,4 +81,7 @@ public class JPQLCollectionAnyVisitorTest { return serializer.toString(); } + private static void assertMatches(String str1, String str2) { + assertTrue(str2, str2.matches(str1)); + } }