Skip to content

Commit 44486ae

Browse files
committed
Replace SheathLeafClauses with simpler SqlQuery-oriented transforms
1 parent c47c559 commit 44486ae

File tree

2 files changed

+65
-18
lines changed

2 files changed

+65
-18
lines changed

quill-engine/src/main/scala/io/getquill/sql/SqlQuery.scala

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,27 @@ import io.getquill.sql.Common.ContainsImpurities
1111

1212
final case class OrderByCriteria(ast: Ast, ordering: PropertyOrdering)
1313

14-
sealed trait FromContext { def quat: Quat }
14+
sealed trait FromContext {
15+
def quat: Quat
16+
def mapAst(f: Ast => Ast): FromContext = this match {
17+
case c: TableContext => c
18+
case QueryContext(query, alias) => QueryContext(query.mapAst(f), alias)
19+
case c: InfixContext => c.mapAsts(f)
20+
case JoinContext(t, a, b, on) => JoinContext(t, a.mapAst(f), b.mapAst(f), f(on))
21+
case FlatJoinContext(t, a, on) => FlatJoinContext(t, a.mapAst(f), f(on))
22+
}
23+
}
1524
final case class TableContext(entity: Entity, alias: Ident) extends FromContext {
1625
override def quat: Quat = entity.quat
1726
}
1827
final case class QueryContext(query: SqlQuery, alias: Ident) extends FromContext {
1928
override def quat: Quat = query.quat
2029
}
21-
final case class InfixContext(infix: Infix, alias: Ident) extends FromContext { override def quat: Quat = infix.quat }
30+
final case class InfixContext(infix: Infix, alias: Ident) extends FromContext {
31+
override def quat: Quat = infix.quat
32+
def mapAsts(f: Ast => Ast): InfixContext =
33+
copy(infix = infix.copy(params = infix.params.map(f)))
34+
}
2235
final case class JoinContext(t: JoinType, a: FromContext, b: FromContext, on: Ast) extends FromContext {
2336
override def quat: Quat = Quat.Tuple(a.quat, b.quat)
2437
}
@@ -29,6 +42,16 @@ final case class FlatJoinContext(t: JoinType, a: FromContext, on: Ast) extends F
2942
sealed trait SqlQuery {
3043
def quat: Quat
3144

45+
def mapAst(f: Ast => Ast): SqlQuery =
46+
this match {
47+
case flatten: FlattenSqlQuery =>
48+
flatten.mapAsts(f)
49+
case SetOperationSqlQuery(a, op, b) =>
50+
SetOperationSqlQuery(a.mapAst(f), op, b.mapAst(f))(quat)
51+
case UnaryOperationSqlQuery(op, q) =>
52+
UnaryOperationSqlQuery(op, q.mapAst(f))(quat)
53+
}
54+
3255
override def toString: String = {
3356
import io.getquill.MirrorSqlDialect._
3457
import io.getquill.idiom.StatementInterpolator._
@@ -83,6 +106,17 @@ final case class FlattenSqlQuery(
83106
)(quatType: Quat)
84107
extends SqlQuery {
85108
override def quat: Quat = quatType
109+
110+
def mapAsts(f: Ast => Ast): FlattenSqlQuery =
111+
copy(
112+
from = from.map(_.mapAst(f)),
113+
where = where.map(f),
114+
groupBy = groupBy.map(f),
115+
orderBy = orderBy.map(o => o.copy(ast = f(o.ast))),
116+
limit = limit.map(f),
117+
offset = offset.map(f),
118+
select = select.map(s => s.copy(ast = f(s.ast)))
119+
)(quatType)
86120
}
87121

88122
object TakeDropFlatten {

quill-engine/src/main/scala/io/getquill/sql/norm/RemoveExtraAlias.scala

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,24 +28,26 @@ case class ValueizeSingleLeafSelects(strategy: NamingStrategy) extends Stateless
2828
def containsAlias(ast: Ast): Boolean =
2929
CollectAst.byType[Ident](ast).exists(id => fromContextAliases.contains(id))
3030

31-
// if it is a leaf add leaf.value
32-
val select =
33-
q.select.map {
34-
// TODO need to do this kind of replacement in Join-by clauses the aggregations etc...
35-
case sv: SelectValue if containsAlias(sv.ast) =>
36-
val reductions = CollectAst.byType[Ident](sv.ast).map(id => id -> valueize(id))
37-
val newAst = BetaReduction(sv.ast, TypeBehavior.ReplaceWithReduction, reductions: _*)
38-
val newSelectValue = SelectValue(newAst, sv.alias, sv.concat)
39-
newSelectValue match {
40-
case sv @ SelectValue(LeafQuat(ast), _, _) => sv.copy(alias = Some("value"))
41-
case _ => newSelectValue
42-
}
43-
case sv @ SelectValue(LeafQuat(ast), _, _) =>
44-
sv.copy(alias = Some("value")) // TODO check if there is no alias already? Probably don't need to since aliasing only really happens in ExpandNestedQueries
45-
case sv => sv
31+
// If there is one single select clause that has a primitive (i.e. Leaf) quat then we can alias it to "value"
32+
// This is the case of `SELECT primitive FROM (SELECT p.age from Person p) AS primitive`
33+
// where we turn it into `SELECT p.name AS value FROM Person p`
34+
def aliasSelects(selectValues: List[SelectValue]) =
35+
selectValues match {
36+
case List(sv @ SelectValue(LeafQuat(ast), _, _)) => List(sv.copy(alias = Some("value")))
37+
case other => other
38+
}
4639

40+
val valuizedQuery =
41+
q.copy(from = from)(q.quat).mapAsts { ast =>
42+
if (containsAlias(ast)) {
43+
val reductions = CollectAst.byType[Ident](ast).filter(id => fromContextAliases.contains(id)).map(id => id -> valueize(id))
44+
BetaReduction(ast, TypeBehavior.ReplaceWithReduction, reductions: _*)
45+
} else {
46+
ast
47+
}
4748
}
48-
q.copy(select = select, from = from)(q.quat)
49+
50+
valuizedQuery.copy(select = aliasSelects(valuizedQuery.select))(q.quat)
4951
}
5052

5153
// Turn every `FROM primitive-x` into a `FROM case-class(x.primitive)`
@@ -57,6 +59,17 @@ case class ValueizeSingleLeafSelects(strategy: NamingStrategy) extends Stateless
5759
other
5860
}
5961

62+
// protected def expandContext(s: FromContext): FromContext =
63+
// s match {
64+
// case QueryContext(q, alias) =>
65+
// QueryContext(apply(q, QueryLevel.Inner), alias)
66+
// case JoinContext(t, a, b, on) =>
67+
// JoinContext(t, expandContext(a), expandContext(b), on)
68+
// case FlatJoinContext(t, a, on) =>
69+
// FlatJoinContext(t, expandContext(a), on)
70+
// case _: TableContext | _: InfixContext => s
71+
// }
72+
6073
private def collectAliases(contexts: List[FromContext]): List[Ident] =
6174
contexts.flatMap {
6275
case c: TableContext => List(c.alias)

0 commit comments

Comments
 (0)