Skip to content

Commit 85bf1e6

Browse files
schaudermp911de
authored andcommitted
DATAJDBC-410 - Properly render NOT IN clauses.
See also: spring-projects/spring-data-r2dbc#177 Original pull request: #167.
1 parent 045c894 commit 85bf1e6

File tree

5 files changed

+166
-5
lines changed

5 files changed

+166
-5
lines changed

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Column.java

+20
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,26 @@ public In in(Select subselect) {
193193
return Conditions.in(this, subselect);
194194
}
195195

196+
/**
197+
* Creates a new {@code not} {@link In} {@link Condition} given right {@link Expression}s.
198+
*
199+
* @param expression right side of the comparison.
200+
* @return the {@link In} condition.
201+
*/
202+
public In notIn(Expression... expression) {
203+
return Conditions.notIn(this, expression);
204+
}
205+
206+
/**
207+
* Creates a new {@code not} {@link In} {@link Condition} given a subselects.
208+
*
209+
* @param subselect right side of the comparison.
210+
* @return the {@link In} condition.
211+
*/
212+
public In notIn(Select subselect) {
213+
return Conditions.notIn(this, subselect);
214+
}
215+
196216
/**
197217
* Creates a {@code IS NULL} condition.
198218
*

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/Conditions.java

+60
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,66 @@ public static In in(Column column, Select subselect) {
192192
return in(column, new SubselectExpression(subselect));
193193
}
194194

195+
/**
196+
* Creates a {@code NOT IN} {@link Condition clause}.
197+
*
198+
* @param columnOrExpression left side of the comparison.
199+
* @param arg IN argument.
200+
* @return the {@link In} condition.
201+
*/
202+
public static In notIn(Expression columnOrExpression, Expression arg) {
203+
204+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
205+
Assert.notNull(arg, "Expression argument must not be null");
206+
207+
return In.create(columnOrExpression, arg);
208+
}
209+
210+
/**
211+
* Creates a new {@code NOT IN} {@link Condition} given left and right {@link Expression}s.
212+
*
213+
* @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
214+
* @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
215+
* @return the {@link In} {@link Condition}.
216+
*/
217+
public static Condition notIn(Expression columnOrExpression, Collection<? extends Expression> expressions) {
218+
219+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
220+
Assert.notNull(expressions, "Expression argument must not be null");
221+
222+
return In.createNotIn(columnOrExpression, new ArrayList<>(expressions));
223+
}
224+
225+
/**
226+
* Creates a new {@code NOT IN} {@link Condition} given left and right {@link Expression}s.
227+
*
228+
* @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
229+
* @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
230+
* @return the {@link In} {@link Condition}.
231+
*/
232+
public static In notIn(Expression columnOrExpression, Expression... expressions) {
233+
234+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
235+
Assert.notNull(expressions, "Expression argument must not be null");
236+
237+
return In.createNotIn(columnOrExpression, Arrays.asList(expressions));
238+
}
239+
240+
/**
241+
* Creates a {@code NOT IN} {@link Condition clause} for a {@link Select subselect}.
242+
*
243+
* @param column the column to compare.
244+
* @param subselect the subselect.
245+
* @return the {@link In} condition.
246+
*/
247+
public static In notIn(Column column, Select subselect) {
248+
249+
Assert.notNull(column, "Column must not be null");
250+
Assert.notNull(subselect, "Subselect must not be null");
251+
252+
return notIn(column, new SubselectExpression(subselect));
253+
}
254+
195255
static class ConstantCondition extends AbstractSegment implements Condition {
196256

197257
private final String condition;

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/In.java

+62-5
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ public class In extends AbstractSegment implements Condition {
3434

3535
private final Expression left;
3636
private final Collection<Expression> expressions;
37+
private final boolean notIn;
3738

38-
private In(Expression left, Collection<Expression> expressions) {
39+
private In(Expression left, Collection<Expression> expressions, boolean notIn) {
3940

4041
super(toArray(left, expressions));
4142

4243
this.left = left;
4344
this.expressions = expressions;
45+
this.notIn = notIn;
4446
}
4547

4648
private static Segment[] toArray(Expression expression, Collection<Expression> expressions) {
@@ -69,7 +71,7 @@ public static In create(Expression columnOrExpression, Expression arg) {
6971
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
7072
Assert.notNull(arg, "Expression argument must not be null");
7173

72-
return new In(columnOrExpression, Collections.singletonList(arg));
74+
return new In(columnOrExpression, Collections.singletonList(arg), false);
7375
}
7476

7577
/**
@@ -84,7 +86,7 @@ public static In create(Expression columnOrExpression, Collection<? extends Expr
8486
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
8587
Assert.notNull(expressions, "Expression argument must not be null");
8688

87-
return new In(columnOrExpression, new ArrayList<>(expressions));
89+
return new In(columnOrExpression, new ArrayList<>(expressions), false);
8890
}
8991

9092
/**
@@ -99,7 +101,58 @@ public static In create(Expression columnOrExpression, Expression... expressions
99101
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
100102
Assert.notNull(expressions, "Expression argument must not be null");
101103

102-
return new In(columnOrExpression, Arrays.asList(expressions));
104+
return new In(columnOrExpression, Arrays.asList(expressions), false);
105+
}
106+
107+
/**
108+
* Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
109+
*
110+
* @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
111+
* @param arg right hand side (collection {@link Expression}) must not be {@literal null}.
112+
* @return the {@link In} {@link Condition}.
113+
*/
114+
public static In createNotIn(Expression columnOrExpression, Expression arg) {
115+
116+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
117+
Assert.notNull(arg, "Expression argument must not be null");
118+
119+
return new In(columnOrExpression, Collections.singletonList(arg), true);
120+
}
121+
122+
/**
123+
* Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
124+
*
125+
* @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
126+
* @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
127+
* @return the {@link In} {@link Condition}.
128+
*/
129+
public static In createNotIn(Expression columnOrExpression, Collection<? extends Expression> expressions) {
130+
131+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
132+
Assert.notNull(expressions, "Expression argument must not be null");
133+
134+
return new In(columnOrExpression, new ArrayList<>(expressions), true);
135+
}
136+
137+
/**
138+
* Creates a new {@link In} {@link Condition} given left and right {@link Expression}s.
139+
*
140+
* @param columnOrExpression left hand side of the {@link Condition} must not be {@literal null}.
141+
* @param expressions right hand side (collection {@link Expression}) must not be {@literal null}.
142+
* @return the {@link In} {@link Condition}.
143+
*/
144+
public static In createNotIn(Expression columnOrExpression, Expression... expressions) {
145+
146+
Assert.notNull(columnOrExpression, "Comparison column or expression must not be null");
147+
Assert.notNull(expressions, "Expression argument must not be null");
148+
149+
return new In(columnOrExpression, Arrays.asList(expressions), true);
150+
}
151+
152+
@Override
153+
public Condition not() {
154+
155+
return new In(left, expressions, !notIn);
103156
}
104157

105158
/*
@@ -108,6 +161,10 @@ public static In create(Expression columnOrExpression, Expression... expressions
108161
*/
109162
@Override
110163
public String toString() {
111-
return left + " IN (" + StringUtils.collectionToDelimitedString(expressions, ", ") + ")";
164+
return left + (notIn ? " NOT" : "") + " IN (" + StringUtils.collectionToDelimitedString(expressions, ", ") + ")";
165+
}
166+
167+
public boolean isNotIn() {
168+
return notIn;
112169
}
113170
}

spring-data-relational/src/main/java/org/springframework/data/relational/core/sql/render/InVisitor.java

+12
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class InVisitor extends TypedSingleConditionRenderSupport<In> {
3030
private final RenderTarget target;
3131
private final StringBuilder part = new StringBuilder();
3232
private boolean needsComma = false;
33+
private boolean notIn = false;
3334

3435
InVisitor(RenderContext context, RenderTarget target) {
3536
super(context);
@@ -52,6 +53,9 @@ Delegation leaveNested(Visitable segment) {
5253

5354
if (part.length() == 0) {
5455
part.append(renderedPart);
56+
if (notIn) {
57+
part.append(" NOT");
58+
}
5559
part.append(" IN (");
5660
} else {
5761
part.append(renderedPart);
@@ -62,6 +66,14 @@ Delegation leaveNested(Visitable segment) {
6266
return super.leaveNested(segment);
6367
}
6468

69+
@Override
70+
Delegation enterMatched(In segment) {
71+
72+
notIn = segment.isNotIn();
73+
74+
return super.enterMatched(segment);
75+
}
76+
6577
/*
6678
* (non-Javadoc)
6779
* @see org.springframework.data.relational.core.sql.render.TypedSubtreeVisitor#leaveMatched(org.springframework.data.relational.core.sql.Visitable)

spring-data-relational/src/test/java/org/springframework/data/relational/core/sql/render/ConditionRendererUnitTests.java

+12
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,16 @@ public void shouldRenderIsNotNull() {
126126

127127
assertThat(sql).endsWith("WHERE my_table.left IS NOT NULL");
128128
}
129+
130+
@Test // DATAJDBC-410
131+
public void shouldRenderNotIn() {
132+
133+
String sql = SqlRenderer.toString(StatementBuilder.select(left).from(table).where(left.in(right).not()).build());
134+
135+
assertThat(sql).endsWith("WHERE my_table.left NOT IN (my_table.right)");
136+
137+
sql = SqlRenderer.toString(StatementBuilder.select(left).from(table).where(left.notIn(right)).build());
138+
139+
assertThat(sql).endsWith("WHERE my_table.left NOT IN (my_table.right)");
140+
}
129141
}

0 commit comments

Comments
 (0)