Skip to content

Commit 6225bd7

Browse files
authored
Support IN clause for three columns (#970)
* Support IN clause for three columns * Specify DBMS to be tested * Specify DBMS to be tested
1 parent dde2c47 commit 6225bd7

File tree

6 files changed

+437
-0
lines changed

6 files changed

+437
-0
lines changed

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/context/Criterion.java

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.Objects;
66
import org.seasar.doma.jdbc.criteria.option.LikeOption;
77
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
8+
import org.seasar.doma.jdbc.criteria.tuple.Tuple3;
89

910
public interface Criterion {
1011
void accept(Visitor visitor);
@@ -298,6 +299,72 @@ public void accept(Visitor visitor) {
298299
}
299300
}
300301

302+
class InTuple3 implements Criterion {
303+
public final Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left;
304+
public final List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> right;
305+
306+
public InTuple3(
307+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left,
308+
List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> right) {
309+
this.left = Objects.requireNonNull(left);
310+
this.right = Objects.requireNonNull(right);
311+
}
312+
313+
@Override
314+
public void accept(Visitor visitor) {
315+
visitor.visit(this);
316+
}
317+
}
318+
319+
class NotInTuple3 implements Criterion {
320+
public final Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left;
321+
public final List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> right;
322+
323+
public NotInTuple3(
324+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left,
325+
List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> right) {
326+
this.left = Objects.requireNonNull(left);
327+
this.right = Objects.requireNonNull(right);
328+
}
329+
330+
@Override
331+
public void accept(Visitor visitor) {
332+
visitor.visit(this);
333+
}
334+
}
335+
336+
class InTuple3SubQuery implements Criterion {
337+
public final Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left;
338+
public final SelectContext right;
339+
340+
public InTuple3SubQuery(
341+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left, SelectContext right) {
342+
this.left = Objects.requireNonNull(left);
343+
this.right = Objects.requireNonNull(right);
344+
}
345+
346+
@Override
347+
public void accept(Visitor visitor) {
348+
visitor.visit(this);
349+
}
350+
}
351+
352+
class NotInTuple3SubQuery implements Criterion {
353+
public final Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left;
354+
public final SelectContext right;
355+
356+
public NotInTuple3SubQuery(
357+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left, SelectContext right) {
358+
this.left = Objects.requireNonNull(left);
359+
this.right = Objects.requireNonNull(right);
360+
}
361+
362+
@Override
363+
public void accept(Visitor visitor) {
364+
visitor.visit(this);
365+
}
366+
}
367+
301368
class Exists implements Criterion {
302369
public final SelectContext context;
303370

@@ -405,6 +472,14 @@ interface Visitor {
405472

406473
void visit(NotInTuple2SubQuery criterion);
407474

475+
void visit(InTuple3 criterion);
476+
477+
void visit(NotInTuple3 criterion);
478+
479+
void visit(InTuple3SubQuery criterion);
480+
481+
void visit(NotInTuple3SubQuery criterion);
482+
408483
void visit(Exists criterion);
409484

410485
void visit(NotExists criterion);

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/declaration/ComparisonDeclaration.java

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
1616
import org.seasar.doma.jdbc.criteria.option.LikeOption;
1717
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
18+
import org.seasar.doma.jdbc.criteria.tuple.Tuple3;
1819

1920
public abstract class ComparisonDeclaration {
2021

@@ -519,6 +520,140 @@ public <PROPERTY1, PROPERTY2> void notIn(
519520
add(new Criterion.NotInTuple2SubQuery(new Tuple2<>(prop1, prop2), right.get()));
520521
}
521522

523+
/**
524+
* Adds a {@code IN} operator.
525+
*
526+
* @param left the left hand operand
527+
* @param right the right hand operand. If this value is null, the query condition doesn't include
528+
* the operator.
529+
* @param <PROPERTY1> the first property type
530+
* @param <PROPERTY2> the second property type
531+
* @param <PROPERTY3> the third property type
532+
* @throws NullPointerException if {@code left} is null
533+
*/
534+
public <PROPERTY1, PROPERTY2, PROPERTY3> void in(
535+
Tuple3<
536+
PropertyMetamodel<PROPERTY1>,
537+
PropertyMetamodel<PROPERTY2>,
538+
PropertyMetamodel<PROPERTY3>>
539+
left,
540+
List<Tuple3<PROPERTY1, PROPERTY2, PROPERTY3>> right) {
541+
Objects.requireNonNull(left);
542+
if (right != null) {
543+
Operand.Prop prop1 = new Operand.Prop(left.getItem1());
544+
Operand.Prop prop2 = new Operand.Prop(left.getItem2());
545+
Operand.Prop prop3 = new Operand.Prop(left.getItem3());
546+
List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> params =
547+
right.stream()
548+
.map(
549+
triple -> {
550+
Operand.Param param1 = new Operand.Param(left.getItem1(), triple.getItem1());
551+
Operand.Param param2 = new Operand.Param(left.getItem2(), triple.getItem2());
552+
Operand.Param param3 = new Operand.Param(left.getItem3(), triple.getItem3());
553+
return new Tuple3<>(param1, param2, param3);
554+
})
555+
.collect(toList());
556+
add(new Criterion.InTuple3(new Tuple3<>(prop1, prop2, prop3), params));
557+
}
558+
}
559+
560+
/**
561+
* Adds a {@code NOT IN} operator.
562+
*
563+
* @param left the left hand operand
564+
* @param right the right hand operand. If this value is null, the query condition doesn't include
565+
* the operator.
566+
* @param <PROPERTY1> the first property type
567+
* @param <PROPERTY2> the second property type
568+
* @param <PROPERTY3> the third property type
569+
* @throws NullPointerException if {@code left} is null
570+
*/
571+
public <PROPERTY1, PROPERTY2, PROPERTY3> void notIn(
572+
Tuple3<
573+
PropertyMetamodel<PROPERTY1>,
574+
PropertyMetamodel<PROPERTY2>,
575+
PropertyMetamodel<PROPERTY3>>
576+
left,
577+
List<Tuple3<PROPERTY1, PROPERTY2, PROPERTY3>> right) {
578+
Objects.requireNonNull(left);
579+
if (right != null) {
580+
Operand.Prop prop1 = new Operand.Prop(left.getItem1());
581+
Operand.Prop prop2 = new Operand.Prop(left.getItem2());
582+
Operand.Prop prop3 = new Operand.Prop(left.getItem3());
583+
List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> params =
584+
right.stream()
585+
.map(
586+
triple -> {
587+
Operand.Param param1 = new Operand.Param(left.getItem1(), triple.getItem1());
588+
Operand.Param param2 = new Operand.Param(left.getItem2(), triple.getItem2());
589+
Operand.Param param3 = new Operand.Param(left.getItem3(), triple.getItem3());
590+
return new Tuple3<>(param1, param2, param3);
591+
})
592+
.collect(toList());
593+
add(new Criterion.NotInTuple3(new Tuple3<>(prop1, prop2, prop3), params));
594+
}
595+
}
596+
597+
/**
598+
* Adds a {@code IN} operator.
599+
*
600+
* @param left the left hand operand
601+
* @param right the right hand operand
602+
* @param <PROPERTY1> the first property type
603+
* @param <PROPERTY2> the second property type
604+
* @param <PROPERTY3> the third property type
605+
* @throws NullPointerException if {@code left} or {@code right} is null
606+
*/
607+
public <PROPERTY1, PROPERTY2, PROPERTY3> void in(
608+
Tuple3<
609+
PropertyMetamodel<PROPERTY1>,
610+
PropertyMetamodel<PROPERTY2>,
611+
PropertyMetamodel<PROPERTY3>>
612+
left,
613+
SubSelectContext<
614+
Tuple3<
615+
PropertyMetamodel<PROPERTY1>,
616+
PropertyMetamodel<PROPERTY2>,
617+
PropertyMetamodel<PROPERTY3>>>
618+
right) {
619+
Objects.requireNonNull(left);
620+
Objects.requireNonNull(right);
621+
Operand.Prop prop1 = new Operand.Prop(left.getItem1());
622+
Operand.Prop prop2 = new Operand.Prop(left.getItem2());
623+
Operand.Prop prop3 = new Operand.Prop(left.getItem3());
624+
add(new Criterion.InTuple3SubQuery(new Tuple3<>(prop1, prop2, prop3), right.get()));
625+
}
626+
627+
/**
628+
* Adds a {@code NOT IN} operator.
629+
*
630+
* @param left the left hand operand
631+
* @param right the right hand operand
632+
* @param <PROPERTY1> the first property type
633+
* @param <PROPERTY2> the second property type
634+
* @param <PROPERTY3> the third property type
635+
* @throws NullPointerException if {@code left} or {@code right} is null
636+
*/
637+
public <PROPERTY1, PROPERTY2, PROPERTY3> void notIn(
638+
Tuple3<
639+
PropertyMetamodel<PROPERTY1>,
640+
PropertyMetamodel<PROPERTY2>,
641+
PropertyMetamodel<PROPERTY3>>
642+
left,
643+
SubSelectContext<
644+
Tuple3<
645+
PropertyMetamodel<PROPERTY1>,
646+
PropertyMetamodel<PROPERTY2>,
647+
PropertyMetamodel<PROPERTY3>>>
648+
right) {
649+
Objects.requireNonNull(left);
650+
Objects.requireNonNull(right);
651+
Operand.Prop prop1 = new Operand.Prop(left.getItem1());
652+
Operand.Prop prop2 = new Operand.Prop(left.getItem2());
653+
Operand.Prop prop3 = new Operand.Prop(left.getItem3());
654+
add(new Criterion.NotInTuple3SubQuery(new Tuple3<>(prop1, prop2, prop3), right.get()));
655+
}
656+
522657
/**
523658
* Adds a {@code EXISTS} operator.
524659
*

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/declaration/SubSelectFromDeclaration.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
1212
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
1313
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
14+
import org.seasar.doma.jdbc.criteria.tuple.Tuple3;
1415

1516
public class SubSelectFromDeclaration<ENTITY> implements SubSelectContext<ENTITY> {
1617

@@ -84,6 +85,21 @@ SubSelectContext<Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY
8485
return () -> context;
8586
}
8687

88+
public <PROPERTY1, PROPERTY2, PROPERTY3>
89+
SubSelectContext<
90+
Tuple3<
91+
PropertyMetamodel<PROPERTY1>,
92+
PropertyMetamodel<PROPERTY2>,
93+
PropertyMetamodel<PROPERTY3>>>
94+
select(
95+
PropertyMetamodel<PROPERTY1> first,
96+
PropertyMetamodel<PROPERTY2> second,
97+
PropertyMetamodel<PROPERTY3> third) {
98+
SelectContext context = declaration.getContext();
99+
context.projection = new Projection.PropertyMetamodels(first, second, third);
100+
return () -> context;
101+
}
102+
87103
public SubSelectContext<List<PropertyMetamodel<?>>> select(
88104
PropertyMetamodel<?> propertyMetamodel1,
89105
PropertyMetamodel<?> propertyMetamodel2,

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/query/BuilderSupport.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
2626
import org.seasar.doma.jdbc.criteria.option.LikeOption;
2727
import org.seasar.doma.jdbc.criteria.tuple.Tuple2;
28+
import org.seasar.doma.jdbc.criteria.tuple.Tuple3;
2829
import org.seasar.doma.jdbc.entity.EntityPropertyType;
2930
import org.seasar.doma.jdbc.entity.EntityType;
3031
import org.seasar.doma.message.Message;
@@ -231,6 +232,26 @@ public void visit(Criterion.NotInTuple2SubQuery c) {
231232
inPairSubQuery(c.left, c.right, true);
232233
}
233234

235+
@Override
236+
public void visit(Criterion.InTuple3 c) {
237+
inTriple(c.left, c.right, false);
238+
}
239+
240+
@Override
241+
public void visit(Criterion.NotInTuple3 c) {
242+
inTriple(c.left, c.right, true);
243+
}
244+
245+
@Override
246+
public void visit(Criterion.InTuple3SubQuery c) {
247+
inTripleSubQuery(c.left, c.right, false);
248+
}
249+
250+
@Override
251+
public void visit(Criterion.NotInTuple3SubQuery c) {
252+
inTripleSubQuery(c.left, c.right, true);
253+
}
254+
234255
@Override
235256
public void visit(Criterion.Exists c) {
236257
exists(c.context, false);
@@ -404,6 +425,58 @@ private void inPairSubQuery(
404425
buf.appendSql(")");
405426
}
406427

428+
private void inTriple(
429+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left,
430+
List<Tuple3<Operand.Param, Operand.Param, Operand.Param>> right,
431+
boolean not) {
432+
buf.appendSql("(");
433+
column(left.getItem1());
434+
buf.appendSql(", ");
435+
column(left.getItem2());
436+
buf.appendSql(", ");
437+
column(left.getItem3());
438+
buf.appendSql(")");
439+
if (not) {
440+
buf.appendSql(" not");
441+
}
442+
buf.appendSql(" in (");
443+
if (right.isEmpty()) {
444+
buf.appendSql("null, null, null");
445+
} else {
446+
right.forEach(
447+
triple -> {
448+
buf.appendSql("(");
449+
param(triple.getItem1());
450+
buf.appendSql(", ");
451+
param(triple.getItem2());
452+
buf.appendSql(", ");
453+
param(triple.getItem3());
454+
buf.appendSql("), ");
455+
});
456+
buf.cutBackSql(2);
457+
}
458+
buf.appendSql(")");
459+
}
460+
461+
private void inTripleSubQuery(
462+
Tuple3<Operand.Prop, Operand.Prop, Operand.Prop> left, SelectContext right, boolean not) {
463+
buf.appendSql("(");
464+
column(left.getItem1());
465+
buf.appendSql(", ");
466+
column(left.getItem2());
467+
buf.appendSql(", ");
468+
column(left.getItem3());
469+
buf.appendSql(")");
470+
if (not) {
471+
buf.appendSql(" not");
472+
}
473+
buf.appendSql(" in (");
474+
AliasManager child = new AliasManager(right, aliasManager);
475+
SelectBuilder builder = new SelectBuilder(config, right, commenter, buf, child);
476+
builder.interpret();
477+
buf.appendSql(")");
478+
}
479+
407480
public void exists(SelectContext context, boolean not) {
408481
if (not) {
409482
buf.appendSql("not ");

0 commit comments

Comments
 (0)