From dd2040093a7770bbf6e8de00a816e8638474f361 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Thu, 8 Aug 2013 17:10:00 +0200 Subject: [PATCH] [#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 --- jOOQ/src/main/java/org/jooq/Clause.java | 15 ++- .../java/org/jooq/impl/BetweenCondition.java | 14 +-- .../main/java/org/jooq/impl/InCondition.java | 4 +- jOOQ/src/main/java/org/jooq/impl/IsNull.java | 8 +- .../org/jooq/impl/RowBetweenCondition.java | 20 ++- .../java/org/jooq/impl/RowInCondition.java | 4 +- .../main/java/org/jooq/impl/RowIsNull.java | 8 +- .../impl/SelectQueryAsExistsCondition.java | 4 +- .../java/org/jooq/test/VisitContextTest.java | 116 ++++++++++++++++++ 9 files changed, 153 insertions(+), 40 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/Clause.java b/jOOQ/src/main/java/org/jooq/Clause.java index 2b0a6fda24..0bf4d8052f 100644 --- a/jOOQ/src/main/java/org/jooq/Clause.java +++ b/jOOQ/src/main/java/org/jooq/Clause.java @@ -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 diff --git a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java index 790c2ca1d4..b03d26bfe7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java @@ -138,13 +138,13 @@ class BetweenCondition extends AbstractCondition implements BetweenAndStep @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 diff --git a/jOOQ/src/main/java/org/jooq/impl/InCondition.java b/jOOQ/src/main/java/org/jooq/impl/InCondition.java index c845f9ace0..657e183447 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/InCondition.java @@ -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 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 field; private final Field[] values; diff --git a/jOOQ/src/main/java/org/jooq/impl/IsNull.java b/jOOQ/src/main/java/org/jooq/impl/IsNull.java index 7831f93153..922133cbd4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/IsNull.java +++ b/jOOQ/src/main/java/org/jooq/impl/IsNull.java @@ -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; diff --git a/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java index 0c7730d009..db52441fe6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java @@ -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 diff --git a/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java index f7628eaccd..2cd855945e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java @@ -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 right; diff --git a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java index 4bab36e1e2..385fdff98d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java +++ b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java @@ -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; diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java index 44ec8e8a86..ed22dffbdb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java @@ -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; diff --git a/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java index 503b894504..80ade48d29 100644 --- a/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java +++ b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java @@ -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> 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++) {