-
Notifications
You must be signed in to change notification settings - Fork 347
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Better ExpandJoin phase using flat-joins
- Loading branch information
1 parent
d0c43aa
commit f744c36
Showing
5 changed files
with
134 additions
and
86 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 40 additions & 54 deletions
94
quill-sql-portable/src/main/scala/io/getquill/sql/norm/ExpandJoin.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,44 @@ | ||
package io.getquill.context.sql.norm | ||
package io.getquill.sql.norm | ||
|
||
import io.getquill.ast._ | ||
import io.getquill.norm.BetaReduction | ||
import io.getquill.norm.Normalize | ||
|
||
/** | ||
* This phase expands inner joins adding the correct aliases so they will function. Unfortunately, | ||
* since it introduces aliases into the clauses that don't actually exist in the inner expressions, | ||
* it is not technically type-safe but will not result in a Quat error since Quats cannot check | ||
* for Ident scoping. For a better implementation, that uses a well-typed FlatMap/FlatJoin cascade, have | ||
* a look here: | ||
* [[https://gist.github.com/deusaquilus/dfb42880656df12779a0afd4f20ef1bb Better Typed ExpandJoin which uses FlatMap/FlatJoin]] | ||
* | ||
* The reason the above implementation is not currently used is because `ExpandNestedQueries` does not | ||
* yet use Quat fields for expansion. Once this is changed, using that implementation here | ||
* should be reconsidered. | ||
*/ | ||
object ExpandJoin { | ||
|
||
def apply(q: Ast) = expand(q, None) | ||
|
||
def expand(q: Ast, id: Option[Ident]) = | ||
Transform(q) { | ||
case q @ Join(_, _, _, Ident(a, _), Ident(b, _), _) => // Ident a and Ident b should have the same Quat, could add an assertion for that | ||
val (qr, tuple) = expandedTuple(q) | ||
Map(qr, id.getOrElse(Ident(s"$a$b", q.quat)), tuple) | ||
} | ||
|
||
private def expandedTuple(q: Join): (Join, Tuple) = | ||
q match { | ||
|
||
case Join(t, a: Join, b: Join, tA, tB, o) => | ||
val (ar, at) = expandedTuple(a) | ||
val (br, bt) = expandedTuple(b) | ||
val or = BetaReduction(o, tA -> at, tB -> bt) | ||
(Join(t, ar, br, tA, tB, or), Tuple(List(at, bt))) | ||
|
||
case Join(t, a: Join, b, tA, tB, o) => | ||
val (ar, at) = expandedTuple(a) | ||
val or = BetaReduction(o, tA -> at) | ||
(Join(t, ar, b, tA, tB, or), Tuple(List(at, tB))) | ||
|
||
case Join(t, a, b: Join, tA, tB, o) => | ||
val (br, bt) = expandedTuple(b) | ||
val or = BetaReduction(o, tB -> bt) | ||
(Join(t, a, br, tA, tB, or), Tuple(List(tA, bt))) | ||
|
||
case q @ Join(t, a, b, tA, tB, on) => | ||
(Join(t, nestedExpand(a, tA), nestedExpand(b, tB), tA, tB, on), Tuple(List(tA, tB))) | ||
} | ||
|
||
private def nestedExpand(q: Ast, id: Ident) = | ||
Normalize(expand(q, Some(id))) match { | ||
case Map(q, _, _) => q | ||
case q => q | ||
object ExpandJoin extends StatelessTransformer { | ||
|
||
object ExcludedFromNesting { | ||
def unapply(ast: Ast) = | ||
ast match { | ||
case _: Entity => true | ||
case _: Infix => true | ||
case _: FlatJoin => true | ||
case _ => false | ||
} | ||
} | ||
|
||
override def apply(e: Query): Query = { | ||
e match { | ||
// Need to nest any map/flatMap clauses found in the `query` slot of a FlatMap or | ||
// Verifier will cause Found an `ON` table reference of a table that is not available when they are | ||
// found in this position. | ||
case fm: FlatMap => | ||
super.apply(fm) match { | ||
case fm @ FlatMap(ExcludedFromNesting(), _, _) => fm | ||
case FlatMap(ent, alias, body) => | ||
FlatMap(Nested(ent), alias, body) | ||
case other => | ||
throw new IllegalArgumentException(s"Result of a flatMap reduction $fm needs to be a flatMap. It was $other.") | ||
} | ||
|
||
// Note that quats in iA, iB shuold not need to change since this is a just a re-wrapping | ||
case Join(typ, a, b, iA, iB, on) => | ||
val a1 = | ||
apply(a) match { | ||
case v @ ExcludedFromNesting() => v | ||
case other => Nested(other) | ||
} | ||
val b1 = apply(b) | ||
FlatMap(a1, iA, Map(FlatJoin(typ, b1, iB, on), iB, Tuple(List(iA, iB)))) | ||
|
||
case _ => super.apply(e) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
quill-sql/src/test/scala/io/getquill/context/sql/norm/ExpandJoinSpec.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters