[#2665] Implement SPI for RenderContext and BindContext listening to

allow for custom SQL transformation

 * Added unit tests for CONDITION clauses
 * Added failing unit test for CONDITION_BETWEEN_SYMMETRIC
This commit is contained in:
Lukas Eder 2013-08-08 17:10:00 +02:00
parent ca106a5dfa
commit dd2040093a
9 changed files with 153 additions and 40 deletions

View File

@ -121,8 +121,8 @@ public enum Clause {
CONDITION,
CONDITION_NULL,
CONDITION_NULL_NOT,
CONDITION_IS_NULL,
CONDITION_IS_NOT_NULL,
// TODO: Should operators be distinguished?
// - LIKE predicate
// - Subselect predicates
@ -130,8 +130,11 @@ public enum Clause {
// - Quantified predicates
CONDITION_COMPARISON,
CONDITION_BETWEEN,
CONDITION_DISTINCT,
CONDITION_DISTINCT_NOT,
CONDITION_BETWEEN_SYMMETRIC,
CONDITION_NOT_BETWEEN,
CONDITION_NOT_BETWEEN_SYMMETRIC,
CONDITION_IS_DISTINCT,
CONDITION_IS_NOT_DISTINCT,
CONDITION_OVERLAPS,
CONDITION_AND,
@ -139,9 +142,9 @@ public enum Clause {
CONDITION_NOT,
CONDITION_IN,
CONDITION_IN_NOT,
CONDITION_NOT_IN,
CONDITION_EXISTS,
CONDITION_EXISTS_NOT,
CONDITION_NOT_EXISTS,
// -------------------------------------------------------------------------
// Clauses that are used in a SELECT statement

View File

@ -138,13 +138,13 @@ class BetweenCondition<T> extends AbstractCondition implements BetweenAndStep<T>
@Override
public final void toSQL(RenderContext context) {
context.visit(field)
.keyword(not ? " not" : "")
.keyword(" between ")
.keyword(symmetric ? "symmetric " : "")
.visit(minValue)
.keyword(" and ")
.visit(maxValue);
context.visit(field);
if (not) context.sql(" ").keyword("not");
context.sql(" ").keyword("between");
if (symmetric) context.sql(" ").keyword("symmetric");
context.sql(" ").visit(minValue);
context.sql(" ").keyword("and");
context.sql(" ").visit(maxValue);
}
@Override

View File

@ -38,7 +38,7 @@ package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_IN;
import static org.jooq.Clause.CONDITION_IN_NOT;
import static org.jooq.Clause.CONDITION_NOT_IN;
import static org.jooq.Comparator.IN;
import static org.jooq.impl.Utils.visitAll;
@ -59,7 +59,7 @@ class InCondition<T> extends AbstractCondition {
private static final long serialVersionUID = -1653924248576930761L;
private static final int IN_LIMIT = 1000;
private static final Clause[] CLAUSES_IN = { CONDITION, CONDITION_IN };
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_IN_NOT };
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_NOT_IN };
private final Field<T> field;
private final Field<?>[] values;

View File

@ -37,8 +37,8 @@
package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_NULL;
import static org.jooq.Clause.CONDITION_NULL_NOT;
import static org.jooq.Clause.CONDITION_IS_NULL;
import static org.jooq.Clause.CONDITION_IS_NOT_NULL;
import org.jooq.BindContext;
import org.jooq.Clause;
@ -51,8 +51,8 @@ import org.jooq.RenderContext;
class IsNull extends AbstractCondition {
private static final long serialVersionUID = -747240442279619486L;
private static final Clause[] CLAUSES_NULL = { CONDITION, CONDITION_NULL };
private static final Clause[] CLAUSES_NULL_NOT = { CONDITION, CONDITION_NULL_NOT };
private static final Clause[] CLAUSES_NULL = { CONDITION, CONDITION_IS_NULL };
private static final Clause[] CLAUSES_NULL_NOT = { CONDITION, CONDITION_IS_NOT_NULL };
private final Field<?> field;
private final boolean isNull;

View File

@ -736,19 +736,13 @@ implements
@Override
public final void toSQL(RenderContext context) {
context.visit(row)
.sql(not ? " " : "")
.keyword(not ? "not" : "")
.sql(" ")
.keyword("between")
.sql(" ")
.keyword(symmetric ? "symmetric" : "")
.sql(symmetric ? " " : "")
.visit(minValue)
.sql(" ")
.keyword("and")
.sql(" ")
.visit(maxValue);
context.visit(row);
if (not) context.sql(" ").keyword("not");
context.sql(" ").keyword("between");
if (symmetric) context.sql(" ").keyword("symmetric");
context.sql(" ").visit(minValue);
context.sql(" ").keyword("and");
context.sql(" ").visit(maxValue);
}
@Override

View File

@ -38,7 +38,7 @@ package org.jooq.impl;
import static java.util.Arrays.asList;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_IN;
import static org.jooq.Clause.CONDITION_IN_NOT;
import static org.jooq.Clause.CONDITION_NOT_IN;
import static org.jooq.Clause.DUMMY;
import static org.jooq.Comparator.EQUALS;
import static org.jooq.Comparator.IN;
@ -75,7 +75,7 @@ class RowInCondition extends AbstractCondition {
*/
private static final long serialVersionUID = -1806139685201770706L;
private static final Clause[] CLAUSES_IN = { CONDITION, CONDITION_IN };
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_IN_NOT };
private static final Clause[] CLAUSES_IN_NOT = { CONDITION, CONDITION_NOT_IN };
private final Row left;
private final QueryPartList<? extends Row> right;

View File

@ -37,8 +37,8 @@ package org.jooq.impl;
import static java.util.Arrays.asList;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_NULL;
import static org.jooq.Clause.CONDITION_NULL_NOT;
import static org.jooq.Clause.CONDITION_IS_NULL;
import static org.jooq.Clause.CONDITION_IS_NOT_NULL;
import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@ -75,8 +75,8 @@ class RowIsNull extends AbstractCondition {
* Generated UID
*/
private static final long serialVersionUID = -1806139685201770706L;
private static final Clause[] CLAUSES_NULL = { CONDITION, CONDITION_NULL };
private static final Clause[] CLAUSES_NULL_NOT = { CONDITION, CONDITION_NULL_NOT };
private static final Clause[] CLAUSES_NULL = { CONDITION, CONDITION_IS_NULL };
private static final Clause[] CLAUSES_NULL_NOT = { CONDITION, CONDITION_IS_NOT_NULL };
private final Row row;
private final boolean isNull;

View File

@ -38,7 +38,7 @@ package org.jooq.impl;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_EXISTS;
import static org.jooq.Clause.CONDITION_EXISTS_NOT;
import static org.jooq.Clause.CONDITION_NOT_EXISTS;
import static org.jooq.impl.ExistsOperator.EXISTS;
import org.jooq.BindContext;
@ -53,7 +53,7 @@ class SelectQueryAsExistsCondition extends AbstractCondition {
private static final long serialVersionUID = 5678338161136603292L;
private static final Clause[] CLAUSES_EXISTS = { CONDITION, CONDITION_EXISTS };
private static final Clause[] CLAUSES_EXISTS_NOT = { CONDITION, CONDITION_EXISTS_NOT };
private static final Clause[] CLAUSES_EXISTS_NOT = { CONDITION, CONDITION_NOT_EXISTS };
private final Select<?> query;
private final ExistsOperator operator;

View File

@ -39,7 +39,13 @@ import static java.util.Arrays.asList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.fail;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_AND;
import static org.jooq.Clause.CONDITION_BETWEEN;
import static org.jooq.Clause.CONDITION_BETWEEN_SYMMETRIC;
import static org.jooq.Clause.CONDITION_COMPARISON;
import static org.jooq.Clause.CONDITION_IS_NOT_NULL;
import static org.jooq.Clause.CONDITION_IS_NULL;
import static org.jooq.Clause.CONDITION_OR;
import static org.jooq.Clause.FIELD;
import static org.jooq.Clause.FIELD_REFERENCE;
import static org.jooq.Clause.FIELD_ROW;
@ -291,6 +297,116 @@ public class VisitContextTest extends AbstractTest {
));
}
@Test
public void test_CONDITION_simple() {
ctx.render(FIELD_ID1.eq(1));
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_COMPARISON),
asList(CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_COMPARISON, FIELD, FIELD_REFERENCE),
asList(CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_COMPARISON, FIELD, FIELD_VALUE)
));
}
@Test
public void test_CONDITION_AND() {
ctx.render(FIELD_ID1.eq(1).and(FIELD_NAME1.isNotNull()));
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_AND),
asList(CONDITION, CONDITION_AND, CONDITION),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_COMPARISON),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_COMPARISON, FIELD, FIELD_REFERENCE),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_COMPARISON, FIELD, FIELD_VALUE),
asList(CONDITION, CONDITION_AND, CONDITION),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_IS_NOT_NULL),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_IS_NOT_NULL, FIELD),
asList(CONDITION, CONDITION_AND, CONDITION, CONDITION_IS_NOT_NULL, FIELD, FIELD_REFERENCE)
));
}
@Test
public void test_CONDITION_OR() {
ctx.render(FIELD_ID1.eq(1).or(FIELD_NAME1.isNull()));
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_OR),
asList(CONDITION, CONDITION_OR, CONDITION),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_COMPARISON),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_COMPARISON, FIELD, FIELD_REFERENCE),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_COMPARISON, FIELD),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_COMPARISON, FIELD, FIELD_VALUE),
asList(CONDITION, CONDITION_OR, CONDITION),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_IS_NULL),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_IS_NULL, FIELD),
asList(CONDITION, CONDITION_OR, CONDITION, CONDITION_IS_NULL, FIELD, FIELD_REFERENCE)
));
}
@Test
public void test_CONDITION_NULL() {
ctx.render(FIELD_ID1.isNull());
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_IS_NULL),
asList(CONDITION, CONDITION_IS_NULL, FIELD),
asList(CONDITION, CONDITION_IS_NULL, FIELD, FIELD_REFERENCE)
));
}
@Test
public void test_CONDITION_NOT_NULL() {
ctx.render(FIELD_ID1.isNotNull());
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_IS_NOT_NULL),
asList(CONDITION, CONDITION_IS_NOT_NULL, FIELD),
asList(CONDITION, CONDITION_IS_NOT_NULL, FIELD, FIELD_REFERENCE)
));
}
@Test
public void test_CONDITION_BETWEEN() {
ctx.render(FIELD_ID1.between(1, 2));
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_BETWEEN),
asList(CONDITION, CONDITION_BETWEEN, FIELD),
asList(CONDITION, CONDITION_BETWEEN, FIELD, FIELD_REFERENCE),
asList(CONDITION, CONDITION_BETWEEN, FIELD),
asList(CONDITION, CONDITION_BETWEEN, FIELD, FIELD_VALUE),
asList(CONDITION, CONDITION_BETWEEN, FIELD),
asList(CONDITION, CONDITION_BETWEEN, FIELD, FIELD_VALUE)
));
}
@Test
public void test_CONDITION_BETWEEN_SYMMETRIC() {
ctx.render(FIELD_ID1.betweenSymmetric(1, 2));
assertEvents(asList(
asList(CONDITION),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD, FIELD_REFERENCE),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD, FIELD_VALUE),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD),
asList(CONDITION, CONDITION_BETWEEN_SYMMETRIC, FIELD, FIELD_VALUE)
));
}
private void assertEvents(List<List<Clause>> expected) {
// This assertion is a bit more verbose to be able to detect errors more easily
for (int i = 0; i < expected.size() && i < listener.clauses.size(); i++) {