Skip to content

Commit 24bab5c

Browse files
committed
Finish joins with subquery support
1 parent e730889 commit 24bab5c

File tree

4 files changed

+151
-3
lines changed

4 files changed

+151
-3
lines changed

src/main/java/org/mybatis/dynamic/sql/select/AbstractQueryExpressionDSL.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ public T leftJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCri
102102
return leftJoin(joinTable, onJoinCriterion, andJoinCriteria);
103103
}
104104

105+
public T leftJoin(Buildable<SelectModel> subQuery, String tableAlias, JoinCriterion onJoinCriterion,
106+
List<JoinCriterion> andJoinCriteria) {
107+
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.LEFT,
108+
andJoinCriteria);
109+
return getThis();
110+
}
111+
105112
public T rightJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
106113
JoinCriterion...andJoinCriteria) {
107114
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.RIGHT, Arrays.asList(andJoinCriteria));
@@ -126,6 +133,13 @@ public T rightJoin(SqlTable joinTable, String tableAlias, JoinCriterion onJoinCr
126133
return rightJoin(joinTable, onJoinCriterion, andJoinCriteria);
127134
}
128135

136+
public T rightJoin(Buildable<SelectModel> subQuery, String tableAlias, JoinCriterion onJoinCriterion,
137+
List<JoinCriterion> andJoinCriteria) {
138+
addJoinSpecificationBuilder(buildSubQuery(subQuery, tableAlias), onJoinCriterion, JoinType.RIGHT,
139+
andJoinCriteria);
140+
return getThis();
141+
}
142+
129143
public T fullJoin(SqlTable joinTable, JoinCriterion onJoinCriterion,
130144
JoinCriterion...andJoinCriteria) {
131145
addJoinSpecificationBuilder(joinTable, onJoinCriterion, JoinType.FULL, Arrays.asList(andJoinCriteria));
@@ -157,8 +171,8 @@ public T fullJoin(Buildable<SelectModel> subQuery, String tableAlias, JoinCriter
157171
return getThis();
158172
}
159173

160-
private void addJoinSpecificationBuilder(TableExpression joinTable, JoinCriterion onJoinCriterion, JoinType joinType,
161-
List<JoinCriterion> andJoinCriteria) {
174+
private void addJoinSpecificationBuilder(TableExpression joinTable, JoinCriterion onJoinCriterion,
175+
JoinType joinType, List<JoinCriterion> andJoinCriteria) {
162176
joinSpecificationBuilders.add(new JoinSpecification.Builder()
163177
.withJoinTable(joinTable)
164178
.withJoinType(joinType)

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinBaseBuilders.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ abstract class KotlinBaseBuilder<W : AbstractWhereDSL<W>, B : KotlinBaseBuilder<
7676
protected abstract fun getWhere(): W
7777
}
7878

79+
@Suppress("TooManyFunctions")
7980
abstract class KotlinBaseJoiningBuilder<T : AbstractQueryExpressionDSL<T, SelectModel>, W : AbstractWhereDSL<W>,
8081
B : KotlinBaseJoiningBuilder<T, W, B>> : KotlinBaseBuilder<W, B>() {
8182

@@ -89,6 +90,15 @@ abstract class KotlinBaseJoiningBuilder<T : AbstractQueryExpressionDSL<T, Select
8990
getDsl().join(table, alias, it.onJoinCriterion, it.andJoinCriteria)
9091
}
9192

93+
fun join(
94+
subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder,
95+
joinCriteria: JoinReceiver
96+
) =
97+
applyJoin(joinCriteria) {
98+
val builder = subQuery(KotlinQualifiedSubQueryBuilder())
99+
getDsl().join(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria)
100+
}
101+
92102
fun fullJoin(table: SqlTable, joinCriteria: JoinReceiver) =
93103
applyJoin(joinCriteria) {
94104
getDsl().fullJoin(table, it.onJoinCriterion, it.andJoinCriteria)
@@ -99,6 +109,15 @@ abstract class KotlinBaseJoiningBuilder<T : AbstractQueryExpressionDSL<T, Select
99109
getDsl().fullJoin(table, alias, it.onJoinCriterion, it.andJoinCriteria)
100110
}
101111

112+
fun fullJoin(
113+
subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder,
114+
joinCriteria: JoinReceiver
115+
) =
116+
applyJoin(joinCriteria) {
117+
val builder = subQuery(KotlinQualifiedSubQueryBuilder())
118+
getDsl().fullJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria)
119+
}
120+
102121
fun leftJoin(table: SqlTable, joinCriteria: JoinReceiver) =
103122
applyJoin(joinCriteria) {
104123
getDsl().leftJoin(table, it.onJoinCriterion, it.andJoinCriteria)
@@ -109,6 +128,15 @@ abstract class KotlinBaseJoiningBuilder<T : AbstractQueryExpressionDSL<T, Select
109128
getDsl().leftJoin(table, alias, it.onJoinCriterion, it.andJoinCriteria)
110129
}
111130

131+
fun leftJoin(
132+
subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder,
133+
joinCriteria: JoinReceiver
134+
) =
135+
applyJoin(joinCriteria) {
136+
val builder = subQuery(KotlinQualifiedSubQueryBuilder())
137+
getDsl().leftJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria)
138+
}
139+
112140
fun rightJoin(table: SqlTable, joinCriteria: JoinReceiver) =
113141
applyJoin(joinCriteria) {
114142
getDsl().rightJoin(table, it.onJoinCriterion, it.andJoinCriteria)
@@ -119,6 +147,15 @@ abstract class KotlinBaseJoiningBuilder<T : AbstractQueryExpressionDSL<T, Select
119147
getDsl().rightJoin(table, alias, it.onJoinCriterion, it.andJoinCriteria)
120148
}
121149

150+
fun rightJoin(
151+
subQuery: KotlinQualifiedSubQueryBuilder.() -> KotlinQualifiedSubQueryBuilder,
152+
joinCriteria: JoinReceiver
153+
) =
154+
applyJoin(joinCriteria) {
155+
val builder = subQuery(KotlinQualifiedSubQueryBuilder())
156+
getDsl().rightJoin(builder.selectBuilder, builder.correlationName, it.onJoinCriterion, it.andJoinCriteria)
157+
}
158+
122159
private fun applyJoin(joinCriteria: JoinReceiver, block: (JoinCollector) -> Unit) =
123160
applySelf {
124161
joinCriteria(JoinCollector()).also(block)

src/main/kotlin/org/mybatis/dynamic/sql/util/kotlin/KotlinModelBuilderFunctions.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import org.mybatis.dynamic.sql.insert.MultiRowInsertDSL
2929
* with the similar functions that build providers for the different rendering
3030
* strategies.
3131
*/
32+
@Suppress("TooManyFunctions")
3233
object KotlinModelBuilderFunctions {
3334
fun count(column: BasicColumn, completer: CountCompleter) =
3435
completer(KotlinCountBuilder(SqlBuilder.countColumn(column))).build()

src/test/kotlin/examples/kotlin/mybatis3/joins/JoinMapperTest.kt

Lines changed: 97 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ class JoinMapperTest {
260260
}
261261

262262
val expectedStatement = "select ol.order_id, quantity, im.item_id, description" +
263-
" from (select * from OrderMaster) om join (select * from OrderLine) ol on om.order_id = ol.order_id" +
263+
" from (select * from OrderMaster) om" +
264+
" join (select * from OrderLine) ol on om.order_id = ol.order_id" +
264265
" full join (select * from ItemMaster) im on ol.item_id = im.item_id" +
265266
" order by order_id, item_id"
266267

@@ -391,6 +392,54 @@ class JoinMapperTest {
391392
}
392393
}
393394

395+
@Test
396+
fun testLeftJoinWithSubQuery() {
397+
newSession().use { session ->
398+
val mapper = session.getMapper(JoinMapper::class.java)
399+
400+
val selectStatement = select(OrderLine.orderId, OrderLine.quantity,
401+
ItemMaster.itemId.qualifiedWith("im"),
402+
ItemMaster.description) {
403+
from(OrderMaster, "om")
404+
join(OrderLine, "ol") {
405+
on(OrderMaster.orderId, equalTo(OrderLine.orderId))
406+
}
407+
leftJoin({
408+
select(ItemMaster.allColumns()) {
409+
from(ItemMaster)
410+
}
411+
+ "im"
412+
}) {
413+
on(OrderLine.itemId, equalTo(ItemMaster.itemId.qualifiedWith("im")))
414+
}
415+
orderBy(OrderLine.orderId, ItemMaster.itemId)
416+
}
417+
418+
val expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" +
419+
" from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +
420+
" left join (select * from ItemMaster) im on ol.item_id = im.item_id" +
421+
" order by order_id, item_id"
422+
423+
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)
424+
425+
val rows = mapper.selectManyMappedRows(selectStatement)
426+
427+
assertThat(rows).hasSize(5)
428+
429+
assertThat(rows[2]).containsExactly(
430+
entry("ORDER_ID", 2),
431+
entry("QUANTITY", 6)
432+
)
433+
434+
assertThat(rows[4]).containsExactly(
435+
entry("ORDER_ID", 2),
436+
entry("QUANTITY", 1),
437+
entry("DESCRIPTION", "Outfield Glove"),
438+
entry("ITEM_ID", 44)
439+
)
440+
}
441+
}
442+
394443
@Test
395444
fun testLeftJoinWithoutAliases() {
396445
newSession().use { session ->
@@ -475,6 +524,53 @@ class JoinMapperTest {
475524
}
476525
}
477526

527+
@Test
528+
fun testRightJoinWithSubQuery() {
529+
newSession().use { session ->
530+
val mapper = session.getMapper(JoinMapper::class.java)
531+
532+
val selectStatement = select(OrderLine.orderId, OrderLine.quantity,
533+
ItemMaster.itemId.qualifiedWith("im"), ItemMaster.description) {
534+
from(OrderMaster, "om")
535+
join(OrderLine, "ol") {
536+
on(OrderMaster.orderId, equalTo(OrderLine.orderId))
537+
}
538+
rightJoin ({
539+
select(ItemMaster.allColumns()) {
540+
from(ItemMaster)
541+
}
542+
+"im"
543+
}) {
544+
on(OrderLine.itemId, equalTo(ItemMaster.itemId.qualifiedWith("im")))
545+
}
546+
orderBy(OrderLine.orderId, ItemMaster.itemId)
547+
}
548+
549+
val expectedStatement = "select ol.order_id, ol.quantity, im.item_id, description" +
550+
" from OrderMaster om join OrderLine ol on om.order_id = ol.order_id" +
551+
" right join (select * from ItemMaster) im on ol.item_id = im.item_id" +
552+
" order by order_id, item_id"
553+
554+
assertThat(selectStatement.selectStatement).isEqualTo(expectedStatement)
555+
556+
val rows = mapper.selectManyMappedRows(selectStatement)
557+
558+
assertThat(rows).hasSize(5)
559+
560+
assertThat(rows[0]).containsExactly(
561+
entry("DESCRIPTION", "Catcher Glove"),
562+
entry("ITEM_ID", 55)
563+
)
564+
565+
assertThat(rows[4]).containsExactly(
566+
entry("ORDER_ID", 2),
567+
entry("QUANTITY", 1),
568+
entry("DESCRIPTION", "Outfield Glove"),
569+
entry("ITEM_ID", 44)
570+
)
571+
}
572+
}
573+
478574
@Test
479575
fun testRightJoinWithoutAliases() {
480576
newSession().use { session ->

0 commit comments

Comments
 (0)