Fix serialization of single item column lists #541

This commit is contained in:
Timo Westkämper 2013-11-05 22:11:51 +02:00
parent 06a7146c2f
commit 6e196a3376
5 changed files with 142 additions and 108 deletions

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Mysema Ltd
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -25,15 +25,15 @@ import com.mysema.query.QueryException;
/**
* ExpressionUtils provides utilities for constructing common operation instances. This class is
* ExpressionUtils provides utilities for constructing common operation instances. This class is
* used internally in Querydsl and is not suitable to be used in cases where DSL methods are needed,
* since the Expression implementations used in this class are minimal internal implementations.
*
*
* @author tiwe
*
*/
public final class ExpressionUtils {
/**
* @param col
* @return
@ -51,10 +51,10 @@ public final class ExpressionUtils {
public static <T> Expression<T> any(CollectionExpression<?, ? super T> col) {
return OperationImpl.create((Class<T>)col.getParameter(0), Ops.QuantOps.ANY, col);
}
/**
* Create the intersection of the given arguments
*
*
* @param exprs
* @return
*/
@ -63,15 +63,15 @@ public final class ExpressionUtils {
Predicate rv = null;
for (Predicate b : exprs) {
if (b != null) {
rv = rv == null ? b : ExpressionUtils.and(rv,b);
}
rv = rv == null ? b : ExpressionUtils.and(rv,b);
}
}
return rv;
}
/**
* Create the intersection of the given arguments
*
*
* @param exprs
* @return
*/
@ -80,15 +80,15 @@ public final class ExpressionUtils {
Predicate rv = null;
for (Predicate b : exprs) {
if (b != null) {
rv = rv == null ? b : ExpressionUtils.and(rv,b);
}
rv = rv == null ? b : ExpressionUtils.and(rv,b);
}
}
return rv;
}
/**
* Create the intersection of the given arguments
*
*
* @param left
* @param right
* @return
@ -96,11 +96,11 @@ public final class ExpressionUtils {
public static Predicate and(Predicate left, Predicate right) {
return PredicateOperation.create(Ops.AND, left, right);
}
/**
* Create the union of the given arguments
*
*
* @param exprs
* @return
*/
@ -109,15 +109,15 @@ public final class ExpressionUtils {
Predicate rv = null;
for (Predicate b : exprs) {
if (b != null) {
rv = rv == null ? b : ExpressionUtils.or(rv,b);
}
rv = rv == null ? b : ExpressionUtils.or(rv,b);
}
}
return rv;
}
/**
* Create the union of the given arguments
*
*
* @param exprs
* @return
*/
@ -126,15 +126,15 @@ public final class ExpressionUtils {
Predicate rv = null;
for (Predicate b : exprs) {
if (b != null) {
rv = rv == null ? b : ExpressionUtils.or(rv,b);
}
rv = rv == null ? b : ExpressionUtils.or(rv,b);
}
}
return rv;
}
/**
* Create an alias expression (source as alias) with the given source and alias
*
*
* @param <D>
* @param source
* @param alias
@ -143,10 +143,10 @@ public final class ExpressionUtils {
public static <D> Expression<D> as(Expression<D> source, Path<D> alias) {
return OperationImpl.create(alias.getType(), Ops.ALIAS, source, alias);
}
/**
* Create an alias expression (source as alias) with the given source and alias
*
*
* @param <D>
* @param source
* @param alias
@ -163,10 +163,10 @@ public final class ExpressionUtils {
public static Expression<Long> count(Expression<?> source) {
return OperationImpl.create(Long.class, Ops.AggOps.COUNT_AGG, source);
}
/**
* Create an left equals constant expression
*
*
* @param <D>
* @param left
* @param constant
@ -175,10 +175,10 @@ public final class ExpressionUtils {
public static <D> Predicate eqConst(Expression<D> left, D constant) {
return eq(left, new ConstantImpl<D>(constant));
}
/**
* Create an left equals right expression
*
*
* @param <D>
* @param left
* @param right
@ -187,10 +187,10 @@ public final class ExpressionUtils {
public static <D> Predicate eq(Expression<D> left, Expression<? extends D> right) {
return PredicateOperation.create(Ops.EQ, left, right);
}
/**
* Create an left in right expression
*
*
* @param <D>
* @param left
* @param right
@ -199,10 +199,10 @@ public final class ExpressionUtils {
public static <D> Predicate in(Expression<D> left, CollectionExpression<?,? extends D> right) {
return PredicateOperation.create(Ops.IN, left, right);
}
/**
* Create an left in right expression
*
*
* @param <D>
* @param left
* @param right
@ -215,37 +215,37 @@ public final class ExpressionUtils {
return PredicateOperation.create(Ops.IN, left, new ConstantImpl<Collection<?>>(right));
}
}
/**
* Create a left is null expression
*
*
* @param left
* @return
*/
public static Predicate isNull(Expression<?> left) {
return PredicateOperation.create(Ops.IS_NULL, left);
}
/**
* Create a left is not null expression
*
*
* @param left
* @return
*/
public static Predicate isNotNull(Expression<?> left) {
return PredicateOperation.create(Ops.IS_NOT_NULL, left);
}
}
/**
* Convert the given like pattern to a regex pattern
*
*
* @param expr
* @return
*/
*/
public static Expression<String> likeToRegex(Expression<String> expr) {
return likeToRegex(expr, true);
}
@SuppressWarnings("unchecked")
public static Expression<String> likeToRegex(Expression<String> expr, boolean matchStartAndEnd) {
@ -257,14 +257,14 @@ public final class ExpressionUtils {
rv.append('^');
}
for (int i = 0; i < like.length(); i++) {
char ch = like.charAt(i);
char ch = like.charAt(i);
if (ch == '.' || ch == '*' || ch == '?') {
rv.append('\\');
} else if (ch == '%') {
rv.append(".*");
rv.append(".*");
continue;
} else if (ch == '_') {
rv.append('.');
rv.append('.');
continue;
}
rv.append(ch);
@ -273,21 +273,21 @@ public final class ExpressionUtils {
rv.append('$');
}
if (!like.equals(rv.toString())) {
return ConstantImpl.create(rv.toString());
}
return ConstantImpl.create(rv.toString());
}
} else if (expr instanceof Operation<?>) {
Operation<?> o = (Operation<?>)expr;
if (o.getOperator() == Ops.CONCAT) {
Expression<String> lhs = likeToRegex((Expression<String>) o.getArg(0), false);
Expression<String> rhs = likeToRegex((Expression<String>) o.getArg(1), false);
if (lhs != o.getArg(0) || rhs != o.getArg(1)) {
return OperationImpl.create(String.class, Ops.CONCAT, lhs, rhs);
}
return OperationImpl.create(String.class, Ops.CONCAT, lhs, rhs);
}
}
}
return expr;
}
/**
* @param exprs
* @return
@ -295,23 +295,28 @@ public final class ExpressionUtils {
public static <T> Expression<T> list(Class<T> clazz, Expression<?>... exprs) {
return list(clazz, ImmutableList.copyOf(exprs));
}
/**
* @param exprs
* @return
*/
public static <T> Expression<T> list(Class<T> clazz, List<? extends Expression<?>> exprs) {
public static <T> Expression<T> list(Class<T> clazz, List<? extends Expression<?>> exprs) {
Expression<T> rv = (Expression<T>)exprs.get(0);
for (int i = 1; i < exprs.size(); i++) {
rv = OperationImpl.create(clazz, Ops.LIST, rv, exprs.get(i));
if (exprs.size() == 1) {
rv = OperationImpl.create(clazz, Ops.SINGLETON, rv, exprs.get(0));
} else {
for (int i = 1; i < exprs.size(); i++) {
rv = OperationImpl.create(clazz, Ops.LIST, rv, exprs.get(i));
}
}
return rv;
}
}
@SuppressWarnings("unchecked")
public static Expression<String> regexToLike(Expression<String> expr) {
if (expr instanceof Constant<?>) {
if (expr instanceof Constant<?>) {
final String str = expr.toString();
final StringBuilder rv = new StringBuilder(str.length() + 2);
boolean escape = false;
@ -331,30 +336,30 @@ public final class ExpressionUtils {
} else if (!escape && (ch == '[' || ch == ']' || ch == '^' || ch == '.' || ch == '*')) {
throw new QueryException("'" + str + "' can't be converted to like form");
} else if (escape && (ch == 'd' || ch == 'D' || ch == 's' || ch == 'S' || ch == 'w' || ch == 'W')) {
throw new QueryException("'" + str + "' can't be converted to like form");
throw new QueryException("'" + str + "' can't be converted to like form");
}
rv.append(ch);
escape = false;
}
if (!rv.toString().equals(str)) {
return ConstantImpl.create(rv.toString());
}
}
} else if (expr instanceof Operation<?>) {
Operation<?> o = (Operation<?>)expr;
if (o.getOperator() == Ops.CONCAT) {
Expression<String> lhs = regexToLike((Expression<String>) o.getArg(0));
Expression<String> rhs = regexToLike((Expression<String>) o.getArg(1));
if (lhs != o.getArg(0) || rhs != o.getArg(1)) {
return OperationImpl.create(String.class, Ops.CONCAT, lhs, rhs);
}
}
return OperationImpl.create(String.class, Ops.CONCAT, lhs, rhs);
}
}
}
return expr;
}
/**
* Create a left not equals constant expression
*
*
* @param <D>
* @param left
* @param constant
@ -363,10 +368,10 @@ public final class ExpressionUtils {
public static <D> Predicate neConst(Expression<D> left, D constant) {
return ne(left, new ConstantImpl<D>(constant));
}
/**
* Create a left not equals right expression
*
*
* @param <D>
* @param left
* @param right
@ -375,10 +380,10 @@ public final class ExpressionUtils {
public static <D> Predicate ne(Expression<D> left, Expression<? super D> right) {
return PredicateOperation.create(Ops.NE, left, right);
}
/**
* Create a left or right expression
*
*
* @param left
* @param right
* @return
@ -386,7 +391,7 @@ public final class ExpressionUtils {
public static Predicate or(Predicate left, Predicate right) {
return PredicateOperation.create(Ops.OR, left, right);
}
/**
* @param args
* @return
@ -401,7 +406,7 @@ public final class ExpressionUtils {
}
return builder.build();
}
/**
* @param args
* @return
@ -418,7 +423,7 @@ public final class ExpressionUtils {
}
return builder.build();
}
/**
* @param expr
* @return
@ -428,10 +433,10 @@ public final class ExpressionUtils {
if (clazz == PathImpl.class || clazz == PredicateOperation.class || clazz == ConstantImpl.class) {
return expr;
} else {
return (Expression<T>) expr.accept(ExtractorVisitor.DEFAULT, null);
}
return (Expression<T>) expr.accept(ExtractorVisitor.DEFAULT, null);
}
}
private ExpressionUtils() {}
}

View File

@ -45,6 +45,8 @@ public final class Ops {
public static final Operator<Object> LIST = new OperatorImpl<Object>(NS, "LIST");
public static final Operator<Object> SINGLETON = new OperatorImpl<Object>(NS, "SINGLETON");
public static final Operator<Integer> ORDINAL = new OperatorImpl<Integer>(NS, "ORDINAL");
public static final Operator<Object> WRAPPED = new OperatorImpl<Object>(NS, "WRAPPED");

View File

@ -45,6 +45,7 @@ public class Templates {
//CHECKSTYLE:OFF
add(Ops.LIST, "{0}, {1}", 40);
add(Ops.SINGLETON, "{0}", 40);
add(Ops.WRAPPED, "({0})");
// boolean

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Mysema Ltd
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -105,9 +105,9 @@ public class CoverageTest {
Ops.ARRAY_SIZE,
Ops.MOD,
Ops.STRING_CAST,
// Ops.DELEGATE,
// Ops.DELEGATE,
Ops.WRAPPED,
Ops.XOR,
Ops.XNOR,
@ -118,10 +118,11 @@ public class CoverageTest {
Ops.CASE_EQ_ELSE,
Ops.LIST,
Ops.SINGLETON,
Ops.COALESCE,
Ops.ORDINAL, // TODO: add support
Ops.MATCHES_IC,
// aggregation
Ops.AggOps.AVG_AGG,
Ops.AggOps.MAX_AGG,

View File

@ -1,6 +1,6 @@
/*
* Copyright 2011, Mysema Ltd
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@ -25,43 +25,44 @@ import com.mysema.query.sql.dml.SQLInsertClause;
import com.mysema.query.sql.dml.SQLUpdateClause;
import com.mysema.query.sql.domain.QEmployee;
import com.mysema.query.sql.domain.QSurvey;
import com.mysema.query.types.Path;
import com.mysema.query.types.SubQueryExpression;
import com.mysema.query.types.path.PathBuilder;
public class SerializationTest {
private static final QSurvey survey = QSurvey.survey;
private final Connection connection = EasyMock.createMock(Connection.class);
@Test
public void InnerJoin() {
public void InnerJoin() {
SQLQuery query = new SQLQuery(connection,SQLTemplates.DEFAULT);
query.from(new QSurvey("s1")).innerJoin(new QSurvey("s2"));
assertEquals("from SURVEY s1\ninner join SURVEY s2", query.toString());
}
@Test
public void LeftJoin() {
public void LeftJoin() {
SQLQuery query = new SQLQuery(connection,SQLTemplates.DEFAULT);
query.from(new QSurvey("s1")).leftJoin(new QSurvey("s2"));
assertEquals("from SURVEY s1\nleft join SURVEY s2", query.toString());
}
@Test
public void RightJoin() {
public void RightJoin() {
SQLQuery query = new SQLQuery(connection,SQLTemplates.DEFAULT);
query.from(new QSurvey("s1")).rightJoin(new QSurvey("s2"));
assertEquals("from SURVEY s1\nright join SURVEY s2", query.toString());
}
@Test
public void FullJoin() {
public void FullJoin() {
SQLQuery query = new SQLQuery(connection,SQLTemplates.DEFAULT);
query.from(new QSurvey("s1")).fullJoin(new QSurvey("s2"));
assertEquals("from SURVEY s1\nfull join SURVEY s2", query.toString());
}
@Test
public void Update() {
SQLUpdateClause updateClause = new SQLUpdateClause(connection,SQLTemplates.DEFAULT,survey);
@ -69,7 +70,7 @@ public class SerializationTest {
updateClause.set(survey.name, (String)null);
assertEquals("update SURVEY\nset ID = ?, NAME = ?", updateClause.toString());
}
@Test
public void Update_Where() {
SQLUpdateClause updateClause = new SQLUpdateClause(connection,SQLTemplates.DEFAULT,survey);
@ -78,7 +79,7 @@ public class SerializationTest {
updateClause.where(survey.name.eq("XXX"));
assertEquals("update SURVEY\nset ID = ?, NAME = ?\nwhere SURVEY.NAME = ?", updateClause.toString());
}
@Test
public void Insert() {
SQLInsertClause insertClause = new SQLInsertClause(connection,SQLTemplates.DEFAULT,survey);
@ -86,7 +87,7 @@ public class SerializationTest {
insertClause.set(survey.name, (String)null);
assertEquals("insert into SURVEY (ID, NAME)\nvalues (?, ?)", insertClause.toString());
}
@Test
public void Delete_with_SubQuery_exists() {
QSurvey survey1 = new QSurvey("s1");
@ -106,7 +107,7 @@ public class SerializationTest {
serializer.serialize(sq.getMetadata(), false);
assertEquals("select nextval('myseq')\nfrom SURVEY SURVEY", serializer.toString());
}
@Test
public void FunctionCall() {
RelationalFunctionCall<String> func = RelationalFunctionCall.create(String.class, "TableValuedFunction", "parameter");
@ -115,7 +116,7 @@ public class SerializationTest {
SubQueryExpression<?> expr = sq.from(survey)
.join(func, funcAlias).on(survey.name.like(funcAlias.getString("prop")).not())
.list(survey.name);
SQLSerializer serializer = new SQLSerializer(new Configuration(new SQLServerTemplates()));
serializer.serialize(expr.getMetadata(), false);
assertEquals("select SURVEY.NAME\n" +
@ -124,7 +125,7 @@ public class SerializationTest {
"on not SURVEY.NAME like tokFunc.prop escape '\\'", serializer.toString());
}
@Test
public void FunctionCall2() {
RelationalFunctionCall<String> func = RelationalFunctionCall.create(String.class, "TableValuedFunction", "parameter");
@ -132,55 +133,79 @@ public class SerializationTest {
SQLQuery q = new SQLQuery(new SQLServerTemplates());
q.from(survey)
.join(func, funcAlias).on(survey.name.like(funcAlias.getString("prop")).not());
assertEquals("from SURVEY SURVEY\n" +
"join TableValuedFunction(?) as tokFunc\n" +
"on not SURVEY.NAME like tokFunc.prop escape '\\'", q.toString());
}
@Test
public void Union() {
SQLQuery q = new SQLQuery(SQLTemplates.DEFAULT);
q.union(new SQLSubQuery().from(survey).list(survey.all()),
new SQLSubQuery().from(survey).list(survey.all()));
assertEquals("(select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n" +
"from SURVEY SURVEY)\n" +
"union\n" +
"(select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n" +
"from SURVEY SURVEY)", q.toString());
}
@Test
public void Union_GroupBy() {
SQLQuery q = new SQLQuery(SQLTemplates.DEFAULT);
q.union(new SQLSubQuery().from(survey).list(survey.all()),
new SQLSubQuery().from(survey).list(survey.all()))
.groupBy(survey.id);
assertEquals("(select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n" +
"from SURVEY SURVEY)\n" +
"union\n" +
"(select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n" +
"from SURVEY SURVEY)\n"+
"group by SURVEY.ID", q.toString());
}
@Test
public void Union2() {
SQLQuery q = new SQLQuery(SQLTemplates.DEFAULT);
q.union(survey,
q.union(survey,
new SQLSubQuery().from(survey).list(survey.all()),
new SQLSubQuery().from(survey).list(survey.all()));
assertEquals("from ((select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n"+
"from SURVEY SURVEY)\n" +
"union\n" +
"(select SURVEY.NAME, SURVEY.NAME2, SURVEY.ID\n" +
"from SURVEY SURVEY)) as SURVEY", q.toString());
}
@Test
public void With() {
QSurvey survey2 = new QSurvey("survey2");
SQLQuery q = new SQLQuery(SQLTemplates.DEFAULT);
q.with(survey, survey.id, survey.name).as(
new SQLSubQuery().from(survey2).list(survey2.id, survey2.name));
assertEquals("with SURVEY (ID, NAME) as (select survey2.ID, survey2.NAME\n" +
"from SURVEY survey2)\n\n" +
"from dual", q.toString());
}
@Test
public void With_SingleColumn() {
QSurvey survey2 = new QSurvey("survey2");
SQLQuery q = new SQLQuery(SQLTemplates.DEFAULT);
q.with(survey, new Path[]{ survey.id }).as(
new SQLSubQuery().from(survey2).list(survey2.id));
assertEquals("with SURVEY (ID) as (select survey2.ID\n" +
"from SURVEY survey2)\n\n" +
"from dual", q.toString());
}
}