Skip to content

Commit bd23360

Browse files
committed
Support the select expression
1 parent d1b5c3a commit bd23360

File tree

10 files changed

+182
-15
lines changed

10 files changed

+182
-15
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,28 @@
11
package org.seasar.doma.jdbc.criteria.context;
22

3+
import java.util.Objects;
4+
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
5+
36
public interface SubSelectContext<RESULT> {
47

58
SelectContext get();
9+
10+
class Single<PROPERTY> implements SubSelectContext<PropertyMetamodel<PROPERTY>> {
11+
private final SelectContext context;
12+
private final PropertyMetamodel<PROPERTY> propertyMetamodel;
13+
14+
public Single(SelectContext context, PropertyMetamodel<PROPERTY> propertyMetamodel) {
15+
this.context = Objects.requireNonNull(context);
16+
this.propertyMetamodel = Objects.requireNonNull(propertyMetamodel);
17+
}
18+
19+
@Override
20+
public SelectContext get() {
21+
return context;
22+
}
23+
24+
public PropertyMetamodel<PROPERTY> getPropertyMetamodel() {
25+
return propertyMetamodel;
26+
}
27+
}
628
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ public void where(Consumer<WhereDeclaration> block) {
7272
}
7373

7474
public void groupBy(PropertyMetamodel<?>... propertyMetamodels) {
75+
Objects.requireNonNull(propertyMetamodels);
7576
context.groupBy.addAll(Arrays.asList(propertyMetamodels));
7677
}
7778

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

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,37 +44,47 @@ public SubSelectFromDeclaration<ENTITY> where(Consumer<WhereDeclaration> block)
4444
return this;
4545
}
4646

47+
public SubSelectFromDeclaration<ENTITY> groupBy(PropertyMetamodel<?>... propertyMetamodels) {
48+
declaration.groupBy(propertyMetamodels);
49+
return this;
50+
}
51+
52+
public SubSelectFromDeclaration<ENTITY> having(Consumer<HavingDeclaration> block) {
53+
declaration.having(block);
54+
return this;
55+
}
56+
4757
public SubSelectFromDeclaration<ENTITY> orderBy(Consumer<OrderByNameDeclaration> block) {
4858
declaration.orderBy(block);
4959
return this;
5060
}
5161

52-
public SubSelectContext<ENTITY> select() {
62+
public SubSelectContext<EntityMetamodel<ENTITY>> select() {
5363
SelectContext context = declaration.getContext();
5464
return () -> context;
5565
}
5666

57-
public SubSelectContext<ENTITY> select(EntityMetamodel<?> entityMetamodel) {
67+
public SubSelectContext<List<PropertyMetamodel<?>>> select(EntityMetamodel<?> entityMetamodel) {
5868
SelectContext context = declaration.getContext();
5969
context.projection = new Projection.PropertyMetamodels(entityMetamodel.allPropertyMetamodels());
6070
return () -> context;
6171
}
6272

63-
public <PROPERTY> SubSelectContext<PROPERTY> select(
64-
PropertyMetamodel<PROPERTY> propertyMetamodel) {
73+
public <PROPERTY> Single<PROPERTY> select(PropertyMetamodel<PROPERTY> propertyMetamodel) {
6574
SelectContext context = declaration.getContext();
6675
context.projection = new Projection.PropertyMetamodels(propertyMetamodel);
67-
return () -> context;
76+
return new Single<>(context, propertyMetamodel);
6877
}
6978

70-
public <PROPERTY1, PROPERTY2> SubSelectContext<Tuple2<PROPERTY1, PROPERTY2>> select(
71-
PropertyMetamodel<PROPERTY1> first, PropertyMetamodel<PROPERTY2> second) {
79+
public <PROPERTY1, PROPERTY2>
80+
SubSelectContext<Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY2>>> select(
81+
PropertyMetamodel<PROPERTY1> first, PropertyMetamodel<PROPERTY2> second) {
7282
SelectContext context = declaration.getContext();
7383
context.projection = new Projection.PropertyMetamodels(first, second);
7484
return () -> context;
7585
}
7686

77-
public SubSelectContext<List<?>> select(
87+
public SubSelectContext<List<PropertyMetamodel<?>>> select(
7888
PropertyMetamodel<?> propertyMetamodel1,
7989
PropertyMetamodel<?> propertyMetamodel2,
8090
PropertyMetamodel<?>... propertyMetamodels) {

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

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,15 @@ public <PROPERTY> void notIn(PropertyMetamodel<PROPERTY> left, List<PROPERTY> ri
9595
right.stream().map(p -> new Operand.Param(left, p)).collect(toList())));
9696
}
9797

98-
public <PROPERTY> void in(PropertyMetamodel<PROPERTY> left, SubSelectContext<PROPERTY> right) {
98+
public <PROPERTY> void in(
99+
PropertyMetamodel<PROPERTY> left, SubSelectContext<PropertyMetamodel<PROPERTY>> right) {
99100
Objects.requireNonNull(left);
100101
Objects.requireNonNull(right);
101102
add(new Criterion.InSubQuery(new Operand.Prop(left), right.get()));
102103
}
103104

104-
public <PROPERTY> void notIn(PropertyMetamodel<PROPERTY> left, SubSelectContext<PROPERTY> right) {
105+
public <PROPERTY> void notIn(
106+
PropertyMetamodel<PROPERTY> left, SubSelectContext<PropertyMetamodel<PROPERTY>> right) {
105107
Objects.requireNonNull(left);
106108
Objects.requireNonNull(right);
107109
add(new Criterion.NotInSubQuery(new Operand.Prop(left), right.get()));
@@ -143,7 +145,7 @@ public <PROPERTY1, PROPERTY2> void notIn(
143145

144146
public <PROPERTY1, PROPERTY2> void in(
145147
Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY2>> left,
146-
SubSelectContext<Tuple2<PROPERTY1, PROPERTY2>> right) {
148+
SubSelectContext<Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY2>>> right) {
147149
Objects.requireNonNull(left);
148150
Objects.requireNonNull(right);
149151
Operand.Prop prop1 = new Operand.Prop(left.getItem1());
@@ -153,7 +155,7 @@ public <PROPERTY1, PROPERTY2> void in(
153155

154156
public <PROPERTY1, PROPERTY2> void notIn(
155157
Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY2>> left,
156-
SubSelectContext<Tuple2<PROPERTY1, PROPERTY2>> right) {
158+
SubSelectContext<Tuple2<PropertyMetamodel<PROPERTY1>, PropertyMetamodel<PROPERTY2>>> right) {
157159
Objects.requireNonNull(left);
158160
Objects.requireNonNull(right);
159161
Operand.Prop prop1 = new Operand.Prop(left.getItem1());

doma-core/src/main/java/org/seasar/doma/jdbc/criteria/expression/Expressions.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@
77
import java.time.LocalTime;
88
import java.util.Objects;
99
import java.util.function.Consumer;
10+
import java.util.function.Function;
1011
import org.seasar.doma.DomaIllegalArgumentException;
1112
import org.seasar.doma.jdbc.criteria.context.Operand;
13+
import org.seasar.doma.jdbc.criteria.context.SubSelectContext;
1214
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
1315

1416
public class Expressions {
@@ -277,4 +279,12 @@ public static <PROPERTY> CaseExpression<PROPERTY> when(
277279
block.accept(caseExpression.new Declaration());
278280
return caseExpression;
279281
}
282+
283+
public static <PROPERTY> SelectExpression<PROPERTY> select(
284+
Function<SelectExpression.Declaration, SubSelectContext.Single<PROPERTY>> block) {
285+
Objects.requireNonNull(block);
286+
SubSelectContext.Single<PROPERTY> subSelectContext =
287+
block.apply(new SelectExpression.Declaration());
288+
return new SelectExpression<>(subSelectContext);
289+
}
280290
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.seasar.doma.jdbc.criteria.expression;
2+
3+
import java.util.Objects;
4+
import org.seasar.doma.jdbc.criteria.context.SelectContext;
5+
import org.seasar.doma.jdbc.criteria.context.SubSelectContext;
6+
import org.seasar.doma.jdbc.criteria.declaration.SubSelectFromDeclaration;
7+
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
8+
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
9+
import org.seasar.doma.jdbc.entity.EntityPropertyType;
10+
11+
public class SelectExpression<PROPERTY> implements PropertyMetamodel<PROPERTY> {
12+
13+
private final SubSelectContext.Single<PROPERTY> subSelectContext;
14+
public final SelectContext context;
15+
public final PropertyMetamodel<?> propertyMetamodel;
16+
17+
public SelectExpression(SubSelectContext.Single<PROPERTY> subSelectContext) {
18+
this.subSelectContext = Objects.requireNonNull(subSelectContext);
19+
this.context = subSelectContext.get();
20+
this.propertyMetamodel = subSelectContext.getPropertyMetamodel();
21+
}
22+
23+
@Override
24+
public Class<?> asClass() {
25+
return propertyMetamodel.asClass();
26+
}
27+
28+
@Override
29+
public EntityPropertyType<?, ?> asType() {
30+
return propertyMetamodel.asType();
31+
}
32+
33+
@Override
34+
public String getName() {
35+
return propertyMetamodel.getName();
36+
}
37+
38+
@Override
39+
public void accept(PropertyMetamodel.Visitor visitor) {
40+
if (visitor instanceof SelectExpression.Visitor) {
41+
SelectExpression.Visitor v = (SelectExpression.Visitor) visitor;
42+
v.visit(this);
43+
}
44+
}
45+
46+
public static class Declaration {
47+
public <ENTITY> SubSelectFromDeclaration<ENTITY> from(EntityMetamodel<ENTITY> entityMetamodel) {
48+
return new SubSelectFromDeclaration<>(entityMetamodel);
49+
}
50+
}
51+
52+
public interface Visitor {
53+
void visit(SelectExpression<?> expression);
54+
}
55+
}

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.seasar.doma.jdbc.criteria.expression.ArithmeticExpression;
1919
import org.seasar.doma.jdbc.criteria.expression.CaseExpression;
2020
import org.seasar.doma.jdbc.criteria.expression.LiteralExpression;
21+
import org.seasar.doma.jdbc.criteria.expression.SelectExpression;
2122
import org.seasar.doma.jdbc.criteria.expression.StringExpression;
2223
import org.seasar.doma.jdbc.criteria.metamodel.EntityMetamodel;
2324
import org.seasar.doma.jdbc.criteria.metamodel.PropertyMetamodel;
@@ -474,7 +475,8 @@ class PropertyMetamodelVisitor
474475
StringExpression.Visitor,
475476
LiteralExpression.Visitor,
476477
AggregateFunction.Visitor,
477-
CaseExpression.Visitor {
478+
CaseExpression.Visitor,
479+
SelectExpression.Visitor {
478480

479481
@Override
480482
public void visit(PropertyMetamodel<?> propertyMetamodel) {
@@ -616,6 +618,15 @@ public void visit(CaseExpression<?> expression) {
616618
}
617619
}
618620

621+
@Override
622+
public void visit(SelectExpression<?> expression) {
623+
buf.appendSql("(");
624+
AliasManager child = new AliasManager(expression.context, aliasManager);
625+
SelectBuilder builder = new SelectBuilder(config, expression.context, commenter, buf, child);
626+
builder.interpret();
627+
buf.appendSql(")");
628+
}
629+
619630
private void binaryOperator(String operator, Operand left, Operand right) {
620631
buf.appendSql("(");
621632
left.accept(operandVisitor);

doma-core/src/test/java/org/seasar/doma/jdbc/criteria/NativeSqlSelectTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import static org.seasar.doma.jdbc.criteria.expression.Expressions.max;
1313
import static org.seasar.doma.jdbc.criteria.expression.Expressions.min;
1414
import static org.seasar.doma.jdbc.criteria.expression.Expressions.rtrim;
15+
import static org.seasar.doma.jdbc.criteria.expression.Expressions.select;
1516
import static org.seasar.doma.jdbc.criteria.expression.Expressions.sum;
1617
import static org.seasar.doma.jdbc.criteria.expression.Expressions.trim;
1718
import static org.seasar.doma.jdbc.criteria.expression.Expressions.upper;
@@ -31,6 +32,7 @@
3132
import org.seasar.doma.jdbc.criteria.entity.Emp;
3233
import org.seasar.doma.jdbc.criteria.entity.Emp_;
3334
import org.seasar.doma.jdbc.criteria.entity.NoIdEmp_;
35+
import org.seasar.doma.jdbc.criteria.expression.SelectExpression;
3436
import org.seasar.doma.jdbc.criteria.option.DistinctOption;
3537
import org.seasar.doma.jdbc.criteria.option.ForUpdateOption;
3638
import org.seasar.doma.jdbc.criteria.option.LikeOption;
@@ -935,7 +937,7 @@ void having_empty() {
935937
}
936938

937939
@Test
938-
void select() {
940+
void test_select() {
939941
Emp_ e = new Emp_();
940942
Buildable<?> stmt = nativeSql.from(e).select(e.id, e.name);
941943

@@ -1309,4 +1311,14 @@ void expression_when_empty() {
13091311
Sql<?> sql = stmt.asSql();
13101312
assertEquals("select 'c' from EMP t0_", sql.getRawSql());
13111313
}
1314+
1315+
@Test
1316+
void expression_select() {
1317+
Emp_ e = new Emp_();
1318+
Emp_ e2 = new Emp_();
1319+
SelectExpression<Integer> expression = select(c -> c.from(e2).select(e2.id));
1320+
Buildable<?> stmt = nativeSql.from(e).select(expression);
1321+
Sql<?> sql = stmt.asSql();
1322+
assertEquals("select (select t1_.ID from EMP t1_) from EMP t0_", sql.getRawSql());
1323+
}
13121324
}

test-criteria/src/test/java/example/NativeSqlSelectTest.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import static org.seasar.doma.jdbc.criteria.expression.Expressions.min;
1919
import static org.seasar.doma.jdbc.criteria.expression.Expressions.mod;
2020
import static org.seasar.doma.jdbc.criteria.expression.Expressions.mul;
21+
import static org.seasar.doma.jdbc.criteria.expression.Expressions.select;
2122
import static org.seasar.doma.jdbc.criteria.expression.Expressions.sub;
2223
import static org.seasar.doma.jdbc.criteria.expression.Expressions.sum;
2324
import static org.seasar.doma.jdbc.criteria.expression.Expressions.when;
@@ -109,7 +110,7 @@ void collect() {
109110
}
110111

111112
@Test
112-
void select() {
113+
void test_select() {
113114
Employee_ e = new Employee_();
114115

115116
List<Employee> list = nativeSql.from(e).select().fetch();
@@ -579,4 +580,15 @@ void expressions_literal_localDate() {
579580

580581
assertEquals(LocalDate.of(2020, 5, 23), date);
581582
}
583+
584+
@Test
585+
void expressions_select() {
586+
Employee_ e = new Employee_();
587+
Employee_ e2 = new Employee_();
588+
589+
Long count =
590+
nativeSql.from(e).select(select(c -> c.from(e2).select(count(e2.employeeId)))).fetchOne();
591+
592+
assertEquals(14L, count);
593+
}
582594
}

test-criteria/src/test/java/example/NativeSqlUpdateTest.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
import static org.seasar.doma.jdbc.criteria.expression.Expressions.add;
77
import static org.seasar.doma.jdbc.criteria.expression.Expressions.concat;
88
import static org.seasar.doma.jdbc.criteria.expression.Expressions.literal;
9+
import static org.seasar.doma.jdbc.criteria.expression.Expressions.max;
10+
import static org.seasar.doma.jdbc.criteria.expression.Expressions.select;
911

12+
import java.math.BigDecimal;
1013
import org.junit.jupiter.api.Test;
1114
import org.junit.jupiter.api.extension.ExtendWith;
1215
import org.seasar.doma.jdbc.Config;
1316
import org.seasar.doma.jdbc.SqlLogType;
1417
import org.seasar.doma.jdbc.criteria.NativeSql;
18+
import org.seasar.doma.jdbc.criteria.expression.SelectExpression;
1519
import org.seasar.doma.jdbc.criteria.statement.EmptyWhereClauseException;
1620

1721
@ExtendWith(Env.class)
@@ -124,4 +128,32 @@ void expressions() {
124128

125129
assertEquals(1, count);
126130
}
131+
132+
@Test
133+
void expression_select() {
134+
Employee_ e = new Employee_();
135+
Employee_ e2 = new Employee_();
136+
Department_ d = new Department_();
137+
138+
SelectExpression<Salary> subSelect =
139+
select(
140+
c ->
141+
c.from(e2)
142+
.innerJoin(d, on -> on.eq(e2.departmentId, d.departmentId))
143+
.where(cc -> cc.eq(e.departmentId, d.departmentId))
144+
.groupBy(d.departmentId)
145+
.select(max(e2.salary)));
146+
147+
int count =
148+
nativeSql
149+
.update(e)
150+
.set(c -> c.value(e.salary, subSelect))
151+
.where(c -> c.eq(e.employeeId, 1))
152+
.execute();
153+
154+
assertEquals(1, count);
155+
156+
Salary salary = nativeSql.from(e).where(c -> c.eq(e.employeeId, 1)).select(e.salary).fetchOne();
157+
assertEquals(0, new BigDecimal("3000").compareTo(salary.getValue()));
158+
}
127159
}

0 commit comments

Comments
 (0)