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 d7b7e0428..480b2e4d2 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 @@ -18,6 +18,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -46,7 +48,9 @@ import com.mysema.query.types.Visitor; public abstract class SerializerBase> implements Visitor { private final StringBuilder builder = new StringBuilder(); - + + private static final Pattern OPERATION = Pattern.compile("\\d+[\\+\\-]\\d+"); + private String constantPrefix = "a"; private String paramPrefix = "p"; @@ -61,6 +65,32 @@ public abstract class SerializerBase> implements Vis private final Templates templates; private final boolean dry; + + private boolean normalize = true; + + public static final String normalize(String queryString) { + StringBuilder rv = new StringBuilder(); + Matcher m = OPERATION.matcher(queryString); + int end = 0; + while (m.find()) { + if (m.start() > end) { + rv.append(queryString.subSequence(end, m.start())); + } + String str = queryString.substring(m.start(), m.end()); + String[] operands = str.split("[\\+\\-]"); + char operator = str.charAt(operands[0].length()); + if (operator == '+') { + rv.append(Integer.valueOf(operands[0]) + Integer.valueOf(operands[1])); + } else { + rv.append(Integer.valueOf(operands[0]) - Integer.valueOf(operands[1])); + } + end = m.end(); + } + if (end < queryString.length()) { + rv.append(queryString.substring(end)); + } + return rv.toString(); + } public SerializerBase(Templates templates) { this(templates, false); @@ -171,10 +201,18 @@ public abstract class SerializerBase> implements Vis public void setAnonParamPrefix(String prefix){ this.anonParamPrefix = prefix; } + + public void setNormalize(boolean normalize) { + this.normalize = normalize; + } @Override public String toString() { - return builder.toString(); + if (normalize) { + return normalize(builder.toString()); + } else { + return builder.toString(); + } } @Override diff --git a/querydsl-core/src/test/java/com/mysema/query/MatchingFiltersFactory.java b/querydsl-core/src/test/java/com/mysema/query/MatchingFiltersFactory.java index f098658a6..539461090 100644 --- a/querydsl-core/src/test/java/com/mysema/query/MatchingFiltersFactory.java +++ b/querydsl-core/src/test/java/com/mysema/query/MatchingFiltersFactory.java @@ -256,6 +256,7 @@ public class MatchingFiltersFactory { if (module != Module.LUCENE){ rv.add(expr.substring(0,1).eq(other.substring(0,1))); + rv.add(expr.substring(1,2).eq(other.substring(1,2))); rv.add(expr.substring(1).eq(other.substring(1))); rv.add(expr.trim().eq(other.trim())); 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 new file mode 100644 index 000000000..7c13fd855 --- /dev/null +++ b/querydsl-core/src/test/java/com/mysema/query/support/SerializerBaseTest.java @@ -0,0 +1,15 @@ +package com.mysema.query.support; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class SerializerBaseTest { + + @Test + public void Normalize() { + assertEquals("3", SerializerBase.normalize("1+2")); + assertEquals("where 3 = 3", SerializerBase.normalize("where 1+2 = 3")); + } + +} diff --git a/querydsl-jpa/derby.log b/querydsl-jpa/derby.log index c62395463..64d4b419d 100644 --- a/querydsl-jpa/derby.log +++ b/querydsl-jpa/derby.log @@ -1,6 +1,6 @@ ---------------------------------------------------------------- -Sat Jan 14 19:25:17 EET 2012: -Booting Derby version The Apache Software Foundation - Apache Derby - 10.8.2.2 - (1181258): instance a816c00e-0134-dd40-7974-000002cca5a0 +Sat Feb 04 17:45:33 EET 2012: +Booting Derby version The Apache Software Foundation - Apache Derby - 10.8.2.2 - (1181258): instance a816c00e-0135-490a-b7a3-000002be71c0 on database directory /home/tiwe/work/querydsl/querydsl-jpa/target/derbydb with class loader sun.misc.Launcher$AppClassLoader@1a16869 Loaded from file:/home/tiwe/.m2/repository/org/apache/derby/derby/10.8.2.2/derby-10.8.2.2.jar java.vendor=Sun Microsystems Inc. diff --git a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLTemplates.java b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLTemplates.java index f69c18cde..a727632eb 100644 --- a/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLTemplates.java +++ b/querydsl-jpa/src/main/java/com/mysema/query/jpa/JPQLTemplates.java @@ -15,7 +15,6 @@ package com.mysema.query.jpa; import javax.annotation.Nullable; -import com.mysema.query.types.Constant; import com.mysema.query.types.Operator; import com.mysema.query.types.OperatorImpl; import com.mysema.query.types.Ops; @@ -74,12 +73,12 @@ public class JPQLTemplates extends Templates { add(Ops.MATCHES, "{0} like {1} escape '\\'", 27); // TODO : support real regexes add(Ops.MATCHES_IC, "{0} like {1} escape '\\'", 27); // TODO : support real regexes add(Ops.LOWER, "lower({0})"); - add(Ops.SUBSTR_1ARG, "substring({0},{1}+1)"); - add(Ops.SUBSTR_2ARGS, "substring({0},{1}+1,{2})"); + add(Ops.SUBSTR_1ARG, "substring({0},{1s}+1)"); + add(Ops.SUBSTR_2ARGS, "substring({0},{1s}+1,{2s}-{1s})"); add(Ops.TRIM, "trim({0})"); add(Ops.UPPER, "upper({0})"); add(Ops.EQ_IGNORE_CASE, "{0l} = {1l}"); - add(Ops.CHAR_AT, "cast(substring({0},{1}+1,1) as char)"); + add(Ops.CHAR_AT, "cast(substring({0},{1s}+1,1) as char)"); add(Ops.STRING_IS_EMPTY, "length({0}) = 0"); add(Ops.STRING_CONTAINS, "{0} like {%1%} escape '\\'"); @@ -89,7 +88,7 @@ public class JPQLTemplates extends Templates { add(Ops.STARTS_WITH, "{0} like {1%} escape '\\'"); add(Ops.STARTS_WITH_IC, "{0l} like {1%%} escape '\\'"); add(Ops.INDEX_OF, "locate({1},{0}) - 1"); - add(Ops.INDEX_OF_2ARGS, "locate({1},{0},{2}+1) - 1"); + add(Ops.INDEX_OF_2ARGS, "locate({1},{0},{2s}+1) - 1"); // date time add(Ops.DateTimeOps.SYSDATE, "sysdate"); 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 a3c60e030..6079cc111 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 @@ -52,7 +52,7 @@ public class JPQLCollectionAnyVisitorTest { 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,:a1+1) = :a2)", serialize(predicate)); + "where cat_kittens in elements(cat.kittens) and substring(cat_kittens.name,2) = :a1)", serialize(predicate)); } @Test diff --git a/querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java b/querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java index 3aadddd5f..6b70367b6 100644 --- a/querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java +++ b/querydsl-sql/src/main/java/com/mysema/query/sql/SQLSerializer.java @@ -562,9 +562,12 @@ public class SQLSerializer extends SerializerBase { && args.get(1) instanceof Constant && operator != Ops.STRING_CAST && operator != Ops.NUMCAST + && operator != Ops.SUBSTR_1ARG + && operator != Ops.CHAR_AT && operator != SQLTemplates.CAST) { constantPaths.add((Path)args.get(0)); - } + } + if (operator.equals(Ops.STRING_CAST)) { String typeName = templates.getTypeForCast(String.class); visitOperation(String.class, SQLTemplates.CAST, Arrays.>asList(args.get(0), ConstantImpl.create(typeName))); diff --git a/querydsl-sql/src/main/java/com/mysema/query/sql/SQLTemplates.java b/querydsl-sql/src/main/java/com/mysema/query/sql/SQLTemplates.java index 8c5b2d749..c7a7f502b 100644 --- a/querydsl-sql/src/main/java/com/mysema/query/sql/SQLTemplates.java +++ b/querydsl-sql/src/main/java/com/mysema/query/sql/SQLTemplates.java @@ -164,13 +164,13 @@ public class SQLTemplates extends Templates { add(Ops.DateTimeOps.YEAR_MONTH, "year({0}) * 100 + month({0})"); // string - add(Ops.CHAR_AT, "cast(substr({0},{1}+1,1) as char)"); + add(Ops.CHAR_AT, "cast(substr({0},{1s}+1,1) as char)"); add(Ops.EQ_IGNORE_CASE, "{0l} = {1l}"); add(Ops.INDEX_OF, "locate({1},{0})-1"); - add(Ops.INDEX_OF_2ARGS, "locate({1},{0},{2}+1)-1"); + add(Ops.INDEX_OF_2ARGS, "locate({1},{0},{2s}+1)-1"); add(Ops.STRING_IS_EMPTY, "length({0}) = 0"); - add(Ops.SUBSTR_1ARG, "substr({0},{1}+1)"); - add(Ops.SUBSTR_2ARGS, "substr({0},{1}+1,{2})"); + add(Ops.SUBSTR_1ARG, "substr({0},{1s}+1)"); + add(Ops.SUBSTR_2ARGS, "substr({0},{1s}+1,{2s}-{1s})"); // like with escape add(Ops.LIKE, "{0} like {1} escape '"+escape+"'");