Allow changing more parts of a select

This commit is contained in:
Eike Kettner 2020-12-15 22:12:44 +01:00
parent f1c4b4adb0
commit 56d6d2e2ac
2 changed files with 99 additions and 5 deletions

View File

@ -15,6 +15,16 @@ sealed trait FromExpr {
def leftJoin(sel: Select, alias: String, on: Condition): Joined =
leftJoin(Relation.SubSelect(sel, alias), on)
/** Prepends the given from expression to existing joins. It will
* replace the current [[FromExpr.From]] value.
*
* If this is a [[FromExpr.From]], it is replaced by the given
* expression. If this is a [[FromExpr.Joined]] then the given
* expression replaces the current `From` and the joins are
* prepended to the existing joins.
*/
def prepend(fe: FromExpr): FromExpr
}
object FromExpr {
@ -25,6 +35,9 @@ object FromExpr {
def leftJoin(other: Relation, on: Condition): Joined =
Joined(this, Vector(Join.LeftJoin(other, on)))
def prepend(fe: FromExpr): FromExpr =
fe
}
object From {
@ -42,6 +55,13 @@ object FromExpr {
def leftJoin(other: Relation, on: Condition): Joined =
Joined(from, joins :+ Join.LeftJoin(other, on))
def prepend(fe: FromExpr): FromExpr =
fe match {
case f: From =>
Joined(f, joins)
case Joined(f, js) =>
Joined(f, js ++ joins)
}
}
sealed trait Relation

View File

@ -6,18 +6,32 @@ import docspell.store.qb.impl.SelectBuilder
import doobie._
/** A sql select statement that allows to change certain parts of the query.
*/
sealed trait Select {
/** Builds the sql select statement into a doobie fragment.
*/
def build: Fragment =
SelectBuilder(this)
/** When using this as a sub-select, an alias is required.
*/
def as(alias: String): SelectExpr.SelectQuery =
SelectExpr.SelectQuery(this, Some(alias))
/** Adds one or more order-by definitions */
def orderBy(ob: OrderBy, obs: OrderBy*): Select
/** Uses the given column for ordering asc */
def orderBy(c: Column[_]): Select =
orderBy(OrderBy(SelectExpr.SelectColumn(c, None), OrderBy.OrderType.Asc))
def groupBy(gb: GroupBy): Select
def groupBy(c: Column[_]): Select =
groupBy(GroupBy(c))
def limit(batch: Batch): Select =
this match {
case Select.Limit(q, _) =>
@ -39,9 +53,16 @@ sealed trait Select {
def appendSelect(e: SelectExpr): Select
def withSelect(e: Nel[SelectExpr]): Select
def changeFrom(f: FromExpr => FromExpr): Select
def changeWhere(f: Condition => Condition): Select
def where(c: Option[Condition]): Select =
where(c.getOrElse(Condition.unit))
def where(c: Condition): Select
}
object Select {
@ -77,21 +98,21 @@ object Select {
where: Condition,
groupBy: Option[GroupBy]
) extends Select {
def group(gb: GroupBy): SimpleSelect =
def groupBy(gb: GroupBy): SimpleSelect =
copy(groupBy = Some(gb))
def distinct: SimpleSelect =
copy(distinctFlag = true)
def where(c: Option[Condition]): SimpleSelect =
where(c.getOrElse(Condition.unit))
def where(c: Condition): SimpleSelect =
copy(where = c)
def appendSelect(e: SelectExpr): SimpleSelect =
copy(projection = projection.append(e))
def withSelect(es: Nel[SelectExpr]): SimpleSelect =
copy(projection = es)
def changeFrom(f: FromExpr => FromExpr): SimpleSelect =
copy(from = f(from))
@ -103,8 +124,11 @@ object Select {
}
case class RawSelect(fragment: Fragment) extends Select {
def groupBy(gb: GroupBy): Select =
sys.error("RawSelect doesn't support adding group by clause")
def appendSelect(e: SelectExpr): RawSelect =
sys.error("RawSelect doesn't support appending select expressions")
sys.error("RawSelect doesn't support appending to select list")
def changeFrom(f: FromExpr => FromExpr): Select =
sys.error("RawSelect doesn't support changing from expression")
@ -114,9 +138,18 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): Ordered =
sys.error("RawSelect doesn't support adding orderBy clause")
def where(c: Condition): Select =
sys.error("RawSelect doesn't support adding where clause")
def withSelect(es: Nel[SelectExpr]): Select =
sys.error("RawSelect doesn't support changing select list")
}
case class Union(q: Select, qs: Vector[Select]) extends Select {
def groupBy(gb: GroupBy): Union =
copy(q = q.groupBy(gb))
def appendSelect(e: SelectExpr): Union =
copy(q = q.appendSelect(e))
@ -128,9 +161,18 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): Ordered =
Ordered(this, ob, obs.toVector)
def where(c: Condition): Union =
copy(q = q.where(c))
def withSelect(es: Nel[SelectExpr]): Union =
copy(q = q.withSelect(es))
}
case class Intersect(q: Select, qs: Vector[Select]) extends Select {
def groupBy(gb: GroupBy): Intersect =
copy(q = q.groupBy(gb))
def appendSelect(e: SelectExpr): Intersect =
copy(q = q.appendSelect(e))
@ -142,10 +184,19 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): Ordered =
Ordered(this, ob, obs.toVector)
def where(c: Condition): Intersect =
copy(q = q.where(c))
def withSelect(es: Nel[SelectExpr]): Intersect =
copy(q = q.withSelect(es))
}
case class Ordered(q: Select, orderBy: OrderBy, orderBys: Vector[OrderBy])
extends Select {
def groupBy(gb: GroupBy): Ordered =
copy(q = q.groupBy(gb))
def appendSelect(e: SelectExpr): Ordered =
copy(q = q.appendSelect(e))
def changeFrom(f: FromExpr => FromExpr): Ordered =
@ -155,9 +206,18 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): Ordered =
Ordered(q, ob, obs.toVector)
def where(c: Condition): Ordered =
copy(q = q.where(c))
def withSelect(es: Nel[SelectExpr]): Ordered =
copy(q = q.withSelect(es))
}
case class Limit(q: Select, batch: Batch) extends Select {
def groupBy(gb: GroupBy): Limit =
copy(q = q.groupBy(gb))
def appendSelect(e: SelectExpr): Limit =
copy(q = q.appendSelect(e))
def changeFrom(f: FromExpr => FromExpr): Limit =
@ -168,9 +228,17 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): Limit =
copy(q = q.orderBy(ob, obs: _*))
def where(c: Condition): Limit =
copy(q = q.where(c))
def withSelect(es: Nel[SelectExpr]): Limit =
copy(q = q.withSelect(es))
}
case class WithCte(cte: CteBind, ctes: Vector[CteBind], q: Select) extends Select {
def groupBy(gb: GroupBy): WithCte =
copy(q = q.groupBy(gb))
def appendSelect(e: SelectExpr): WithCte =
copy(q = q.appendSelect(e))
@ -182,5 +250,11 @@ object Select {
def orderBy(ob: OrderBy, obs: OrderBy*): WithCte =
copy(q = q.orderBy(ob, obs: _*))
def where(c: Condition): WithCte =
copy(q = q.where(c))
def withSelect(es: Nel[SelectExpr]): WithCte =
copy(q = q.withSelect(es))
}
}