Kristian Nilsen
06/11/2024, 7:24 AMval aJoins: () -> Join = {
EntityA.join(
SomeEntity,
joinType = JoinType.INNER,
additionalConstraint = ...
)
.join(
AnotherEntity,
joinType = JoinType.INNER,
additionalConstraint = ....
)
.join(
SomeOtherEntity,
joinType = JoinType.LEFT,
additionalConstraint = ...
)
}
"B" contains the following joins:
val bJoins: () -> Join = {
super.aJoins().join(
EntityB,
joinType = JoinType.INNER,
onColumn = ...,
otherColumn = ...
).join(
TypeOfUsageParameterEntity,
joinType = JoinType.LEFT,
onColumn = ...,
otherColumn = ...
)
}
And finally, "C" contains the following join
private val query: () -> Query = {
super.bJoins().join(
EntityC,
joinType = JoinType.INNER,
onColumn = ...,
otherColumn = ...
).selectAll()
}
Thus, for a select all statement in C I depend on joins from both parent classes. Is there a better way to achieve this using the DSL?
Appreciate any help and pointers I can getOleg Babichev
06/13/2024, 7:39 AMDAO classes
, but is the actual question about DSL
queries?
Additionally, just to clarify, are you dealing with two types of SQL queries? The first one being a comprehensive query like:
select ...
from A
join some ...
join another ...
join some_other ...
join B ...
join type_of_usage_parameter
join C
And the second type where you only want entries from C, like:
select ...
from A
join B ...
join C ...
?
And the question is more about how to use both of these approaches with minimal code duplication?
If so, we can consider how to better organize the code. I tried to write a similar table structure and query it in two different ways. Finally, I wrote some extension functions to the tables that allow joining specific tables to others:
object A : IntIdTable() {
fun Table.withAJoins() = joinOtherToA().joinSomeOtherToA().joinBToA()
}
object Other : IntIdTable() {
val a = reference("a", A.id)
fun Join.joinOtherToA() = join(Other, JoinType.LEFT, onColumn = Other.a, otherColumn = A.id)
fun Table.joinOtherToA() = Join(this).joinOtherToA()
}
object SomeOther : IntIdTable() {
val a = reference("a", A.id)
fun Join.joinSomeOtherToA() = join(SomeOther, JoinType.LEFT, onColumn = SomeOther.a, otherColumn = A.id)
fun Table.joinSomeOtherToA() = Join(this).joinSomeOtherToA()
}
object B : IntIdTable() {
val a = reference("a", A.id)
fun Join.joinBToA() = join(B, JoinType.LEFT, onColumn = B.a, otherColumn = A.id)
fun Table.joinBToA() = Join(this).joinBToA()
fun Join.withBJoins() = joinTypeOfUsageParameterToB().joinCToB()
}
object TypeOfUsageParameter : IntIdTable() {
val b = reference("b", B.id)
fun Join.joinTypeOfUsageParameterToB() = join(TypeOfUsageParameter, JoinType.LEFT, onColumn = TypeOfUsageParameter.b, otherColumn = B.id)
}
object C : IntIdTable() {
val b = reference("b", B.id)
fun Join.joinCToB() = join(C, JoinType.LEFT, onColumn = C.b, otherColumn = B.id)
}
fun test() {
A
.join(B, JoinType.LEFT, onColumn = B.a, otherColumn = A.id)
.join(C, JoinType.LEFT, onColumn = C.b, otherColumn = B.id)
val fullQuery = A.withAJoins().withBJoins()
val shortQuery = A.joinBToA().joinCToB()
}
The join<Table1>To<Table2>
functions help organize possible joins. The with<Table>Joins
methods know all possible joins to the current table and allow for getting a full set of joins for it.
Thus, the full join will look like A.withAJoins().withBJoins()
and the shorter one like A.joinBToA().joinCToB()
. If you need all joins of A but not the joins of B, you can use A.withAJoins().joinCToB()
.
This is just one way to organize large queries. It would be great if others who have faced similar issues could share their solutions or thoughts.Kristian Nilsen
07/24/2024, 12:45 PMOleg Babichev
07/25/2024, 8:55 AM