#94 fixed JPA substring handling

This commit is contained in:
Timo Westkämper 2012-02-04 18:47:56 +02:00
parent 433fa77327
commit 3ca2dbcc2c
8 changed files with 71 additions and 15 deletions

View File

@ -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<S extends SerializerBase<S>> implements Visitor<Void,Void> {
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<S extends SerializerBase<S>> 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<S extends SerializerBase<S>> 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

View File

@ -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()));

View File

@ -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"));
}
}

View File

@ -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.

View File

@ -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");

View File

@ -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

View File

@ -562,9 +562,12 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
&& 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.<Expression<?>>asList(args.get(0), ConstantImpl.create(typeName)));

View File

@ -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+"'");