diff --git a/pom.xml b/pom.xml
index 2220303342..8a72b2eade 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.springframework.data
spring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
pom
Spring Data Relational Parent
diff --git a/spring-data-jdbc-distribution/pom.xml b/spring-data-jdbc-distribution/pom.xml
index 71b9a3c782..83b19c7d2a 100644
--- a/spring-data-jdbc-distribution/pom.xml
+++ b/spring-data-jdbc-distribution/pom.xml
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
../pom.xml
diff --git a/spring-data-jdbc/pom.xml b/spring-data-jdbc/pom.xml
index d33566bc88..5d6588cadf 100644
--- a/spring-data-jdbc/pom.xml
+++ b/spring-data-jdbc/pom.xml
@@ -5,7 +5,7 @@
4.0.0
spring-data-jdbc
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
Spring Data JDBC
Spring Data module for JDBC repositories.
@@ -14,7 +14,7 @@
org.springframework.data
spring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
diff --git a/spring-data-relational/pom.xml b/spring-data-relational/pom.xml
index fa7f2f4873..3f6279909c 100644
--- a/spring-data-relational/pom.xml
+++ b/spring-data-relational/pom.xml
@@ -5,7 +5,7 @@
4.0.0
spring-data-relational
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
Spring Data Relational
Spring Data Relational support
@@ -13,7 +13,7 @@
org.springframework.data
spring-data-relational-parent
- 1.1.0.BUILD-SNAPSHOT
+ 1.1.0.DATAJDBC-410-SNAPSHOT
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
index 97e71b2a6d..aba998fa2f 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java
@@ -193,6 +193,26 @@ public In in(Select subselect) {
return Conditions.in(this, subselect);
}
+ /**
+ * Creates a new {@code not} {@link In} {@link Condition} given right {@link Expression}s.
+ *
+ * @param expression right side of the comparison.
+ * @return the {@link In} condition.
+ */
+ public In notIn(Expression... expression) {
+ return Conditions.notIn(this, expression);
+ }
+
+ /**
+ * Creates a new {@code not} {@link In} {@link Condition} given a subselects.
+ *
+ * @param subselect right side of the comparison.
+ * @return the {@link In} condition.
+ */
+ public In notIn(Select subselect) {
+ return Conditions.notIn(this, subselect);
+ }
+
/**
* Creates a {@code IS NULL} condition.
*
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Conditions.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Conditions.java
index ea71b0c63c..d20055b386 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Conditions.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Conditions.java
@@ -192,6 +192,66 @@ public static In in(Column column, Select subselect) {
return in(column, new SubselectExpression(subselect));
}
+ /**
+ * Creates a {@code NOT IN} {@link Condition clause}.
+ *
+ * @param columnOrExpression left side of the comparison.
+ * @param arg IN argument.
+ * @return the {@link In} condition.
+ */
+ public static In notIn(Expression columnOrExpression, Expression arg) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(arg, "Expression argument must not be null");
+
+ return In.create(columnOrExpression, arg);
+ }
+
+ /**
+ * Creates a new {@code NOT IN} {@link Condition} given left and right {@link Expression}s.
+ *
+ * @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
+ * @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
+ * @return the {@link In} {@link Condition}.
+ */
+ public static Condition notIn(Expression columnOrExpression, Collection extends Expression> expressions) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(expressions, "Expression argument must not be null");
+
+ return In.createNotIn(columnOrExpression, new ArrayList<>(expressions));
+ }
+
+ /**
+ * Creates a new {@code NOT IN} {@link Condition} given left and right {@link Expression}s.
+ *
+ * @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
+ * @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
+ * @return the {@link In} {@link Condition}.
+ */
+ public static In notIn(Expression columnOrExpression, Expression... expressions) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(expressions, "Expression argument must not be null");
+
+ return In.createNotIn(columnOrExpression, Arrays.asList(expressions));
+ }
+
+ /**
+ * Creates a {@code NOT IN} {@link Condition clause} for a {@link Select subselect}.
+ *
+ * @param column the column to compare.
+ * @param subselect the subselect.
+ * @return the {@link In} condition.
+ */
+ public static In notIn(Column column, Select subselect) {
+
+ Assert.notNull(column, "Column must not be null");
+ Assert.notNull(subselect, "Subselect must not be null");
+
+ return notIn(column, new SubselectExpression(subselect));
+ }
+
static class ConstantCondition extends AbstractSegment implements Condition {
private final String condition;
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/In.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/In.java
index 16ff59be10..a590a9acb9 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/In.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/In.java
@@ -34,13 +34,15 @@ public class In extends AbstractSegment implements Condition {
private final Expression left;
private final Collection expressions;
+ private final boolean notIn;
- private In(Expression left, Collection expressions) {
+ private In(Expression left, Collection expressions, boolean notIn) {
super(toArray(left, expressions));
this.left = left;
this.expressions = expressions;
+ this.notIn = notIn;
}
private static Segment[] toArray(Expression expression, Collection expressions) {
@@ -69,7 +71,7 @@ public static In create(Expression columnOrExpression, Expression arg) {
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
Assert.notNull(arg, "Expression argument must not be null");
- return new In(columnOrExpression, Collections.singletonList(arg));
+ return new In(columnOrExpression, Collections.singletonList(arg), false);
}
/**
@@ -84,7 +86,7 @@ public static In create(Expression columnOrExpression, Collection extends Expr
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
Assert.notNull(expressions, "Expression argument must not be null");
- return new In(columnOrExpression, new ArrayList<>(expressions));
+ return new In(columnOrExpression, new ArrayList<>(expressions), false);
}
/**
@@ -99,7 +101,58 @@ public static In create(Expression columnOrExpression, Expression... expressions
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
Assert.notNull(expressions, "Expression argument must not be null");
- return new In(columnOrExpression, Arrays.asList(expressions));
+ return new In(columnOrExpression, Arrays.asList(expressions), false);
+ }
+
+ /**
+ * Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
+ *
+ * @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
+ * @param arg right hand side (collection {@link Expression}) must not be {@literal null}.
+ * @return the {@link In} {@link Condition}.
+ */
+ public static In createNotIn(Expression columnOrExpression, Expression arg) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(arg, "Expression argument must not be null");
+
+ return new In(columnOrExpression, Collections.singletonList(arg), true);
+ }
+
+ /**
+ * Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
+ *
+ * @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
+ * @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
+ * @return the {@link In} {@link Condition}.
+ */
+ public static In createNotIn(Expression columnOrExpression, Collection extends Expression> expressions) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(expressions, "Expression argument must not be null");
+
+ return new In(columnOrExpression, new ArrayList<>(expressions), true);
+ }
+
+ /**
+ * Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
+ *
+ * @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
+ * @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
+ * @return the {@link In} {@link Condition}.
+ */
+ public static In createNotIn(Expression columnOrExpression, Expression... expressions) {
+
+ Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
+ Assert.notNull(expressions, "Expression argument must not be null");
+
+ return new In(columnOrExpression, Arrays.asList(expressions), true);
+ }
+
+ @Override
+ public Condition not() {
+
+ return new In(left, expressions, !notIn);
}
/*
@@ -108,6 +161,10 @@ public static In create(Expression columnOrExpression, Expression... expressions
*/
@Override
public String toString() {
- return left + " IN (" + StringUtils.collectionToDelimitedString(expressions, ", ") + ")";
+ return left + (notIn ? " NOT" : "") + " IN (" + StringUtils.collectionToDelimitedString(expressions, ", ") + ")";
+ }
+
+ public boolean isNotIn() {
+ return notIn;
}
}
diff --git a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/InVisitor.java b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/InVisitor.java
index eee1af8f81..2d47b1913b 100644
--- a/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/InVisitor.java
+++ b/spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/InVisitor.java
@@ -30,6 +30,7 @@ class InVisitor extends TypedSingleConditionRenderSupport {
private final RenderTarget target;
private final StringBuilder part = new StringBuilder();
private boolean needsComma = false;
+ private boolean notIn = false;
InVisitor(RenderContext context, RenderTarget target) {
super(context);
@@ -52,6 +53,9 @@ Delegation leaveNested(Visitable segment) {
if (part.length() == 0) {
part.append(renderedPart);
+ if (notIn) {
+ part.append(" NOT");
+ }
part.append(" IN (");
} else {
part.append(renderedPart);
@@ -62,6 +66,14 @@ Delegation leaveNested(Visitable segment) {
return super.leaveNested(segment);
}
+ @Override
+ Delegation enterMatched(In segment) {
+
+ notIn = segment.isNotIn();
+
+ return super.enterMatched(segment);
+ }
+
/*
* (non-Javadoc)
* @see org.springframework.data.relational.core.sql.render.TypedSubtreeVisitor#leaveMatched(org.springframework.data.relational.core.sql.Visitable)
diff --git a/spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/ConditionRendererUnitTests.java b/spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/ConditionRendererUnitTests.java
index b8c9b6e6a1..6f9c65101e 100644
--- a/spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/ConditionRendererUnitTests.java
+++ b/spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/ConditionRendererUnitTests.java
@@ -126,4 +126,16 @@ public void shouldRenderIsNotNull() {
assertThat(sql).endsWith("WHERE my_table.left IS NOT NULL");
}
+
+ @Test // DATAJDBC-410
+ public void shouldRenderNotIn() {
+
+ String sql = SqlRenderer.toString(StatementBuilder.select(left).from(table).where(left.in(right).not()).build());
+
+ assertThat(sql).endsWith("WHERE my_table.left NOT IN (my_table.right)");
+
+ sql = SqlRenderer.toString(StatementBuilder.select(left).from(table).where(left.notIn(right)).build());
+
+ assertThat(sql).endsWith("WHERE my_table.left NOT IN (my_table.right)");
+ }
}