mirror of
https://github.com/querydsl/querydsl.git
synced 2026-07-03 21:07:49 +08:00
#176 improved collection.any() serialization
This commit is contained in:
parent
6bb37746af
commit
80264eccc7
@ -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<Expression<?>,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<Expression<?>,Context>{
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Expression<?> visit(SubQueryExpression<?> expr, Context context) {
|
||||
return expr;
|
||||
|
||||
@ -59,6 +59,10 @@ public abstract class SerializerBase<S extends SerializerBase<S>> 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<S extends SerializerBase<S>> 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();
|
||||
|
||||
@ -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<Boolean> 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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -330,17 +330,6 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private SingularAttribute<?,?> getIdProperty(EntityType entity) {
|
||||
Set<SingularAttribute> 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<JPQLSerializer> {
|
||||
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<JPQLSerializer> {
|
||||
}
|
||||
|
||||
} else if (operator.equals(Ops.INSTANCE_OF)) {
|
||||
if (templates.isTypeAsString()) {
|
||||
List<Expression<?>> newArgs = new ArrayList<Expression<?>>(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.<Expression<?>>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<JPQLSerializer> {
|
||||
wrapElements = old;
|
||||
}
|
||||
|
||||
private void visitNumCast(List<? extends Expression<?>> args) {
|
||||
Class<?> targetType = (Class<?>) ((Constant<?>) args.get(1)).getConstant();
|
||||
String typeName = targetType.getSimpleName().toLowerCase(Locale.ENGLISH);
|
||||
visitOperation(targetType, JPQLTemplates.CAST, Arrays.<Expression<?>>asList(args.get(0), ConstantImpl.create(typeName)));
|
||||
}
|
||||
|
||||
private void visitInstanceOf(Class<?> type, Operator<?> operator,
|
||||
List<? extends Expression<?>> args) {
|
||||
if (templates.isTypeAsString()) {
|
||||
List<Expression<?>> newArgs = new ArrayList<Expression<?>>(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<? extends Expression<?>> args) {
|
||||
@ -410,7 +407,9 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
|
||||
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<JPQLSerializer> {
|
||||
super.visitOperation(type, operator, args);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private SingularAttribute<?,?> getIdProperty(EntityType entity) {
|
||||
Set<SingularAttribute> singularAttributes = entity.getSingularAttributes();
|
||||
for (SingularAttribute singularAttribute : singularAttributes) {
|
||||
if (singularAttribute.isId()){
|
||||
return singularAttribute;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void visitAnyInPath(Class<?> type, List<? extends Expression<?>> args) {
|
||||
if (!templates.isEnumInPathSupported() && args.get(0) instanceof Constant && Enum.class.isAssignableFrom(args.get(0).getType())) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<Boolean> 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));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user