mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-05 10:59:33 +00:00
Extends query builder
This commit is contained in:
parent
35c62049f5
commit
5e2c5d2a50
@ -150,7 +150,7 @@ object RegexNerFile {
|
|||||||
)
|
)
|
||||||
val t = Column[Timestamp]("t", TableDef(""))
|
val t = Column[Timestamp]("t", TableDef(""))
|
||||||
|
|
||||||
run(select(max(t)), fromSubSelect(sql).as("x"))
|
run(select(max(t)), from(sql, "x"))
|
||||||
.query[Option[Timestamp]]
|
.query[Option[Timestamp]]
|
||||||
.option
|
.option
|
||||||
.map(_.flatten)
|
.map(_.flatten)
|
||||||
|
@ -59,8 +59,8 @@ trait DSL extends DoobieMeta {
|
|||||||
def from(table: TableDef): FromExpr.From =
|
def from(table: TableDef): FromExpr.From =
|
||||||
FromExpr.From(table)
|
FromExpr.From(table)
|
||||||
|
|
||||||
def fromSubSelect(sel: Select): FromExpr.SubSelect =
|
def from(sel: Select, alias: String): FromExpr.From =
|
||||||
FromExpr.SubSelect(sel, "x")
|
FromExpr.From(sel, alias)
|
||||||
|
|
||||||
def count(c: Column[_]): DBFunction =
|
def count(c: Column[_]): DBFunction =
|
||||||
DBFunction.Count(c)
|
DBFunction.Count(c)
|
||||||
|
@ -4,24 +4,55 @@ sealed trait FromExpr
|
|||||||
|
|
||||||
object FromExpr {
|
object FromExpr {
|
||||||
|
|
||||||
case class From(table: TableDef) extends FromExpr {
|
case class From(table: Relation) extends FromExpr {
|
||||||
def innerJoin(other: TableDef, on: Condition): Joined =
|
def innerJoin(other: Relation, on: Condition): Joined =
|
||||||
Joined(this, Vector(Join.InnerJoin(other, on)))
|
Joined(this, Vector(Join.InnerJoin(other, on)))
|
||||||
|
|
||||||
def leftJoin(other: TableDef, on: Condition): Joined =
|
def innerJoin(other: TableDef, on: Condition): Joined =
|
||||||
|
innerJoin(Relation.Table(other), on)
|
||||||
|
|
||||||
|
def leftJoin(other: Relation, on: Condition): Joined =
|
||||||
Joined(this, Vector(Join.LeftJoin(other, on)))
|
Joined(this, Vector(Join.LeftJoin(other, on)))
|
||||||
|
|
||||||
|
def leftJoin(other: TableDef, on: Condition): Joined =
|
||||||
|
leftJoin(Relation.Table(other), on)
|
||||||
|
}
|
||||||
|
|
||||||
|
object From {
|
||||||
|
def apply(td: TableDef): From =
|
||||||
|
From(Relation.Table(td))
|
||||||
|
|
||||||
|
def apply(select: Select, alias: String): From =
|
||||||
|
From(Relation.SubSelect(select, alias))
|
||||||
}
|
}
|
||||||
|
|
||||||
case class Joined(from: From, joins: Vector[Join]) extends FromExpr {
|
case class Joined(from: From, joins: Vector[Join]) extends FromExpr {
|
||||||
def innerJoin(other: TableDef, on: Condition): Joined =
|
def innerJoin(other: Relation, on: Condition): Joined =
|
||||||
Joined(from, joins :+ Join.InnerJoin(other, on))
|
Joined(from, joins :+ Join.InnerJoin(other, on))
|
||||||
|
|
||||||
def leftJoin(other: TableDef, on: Condition): Joined =
|
def innerJoin(other: TableDef, on: Condition): Joined =
|
||||||
|
innerJoin(Relation.Table(other), on)
|
||||||
|
|
||||||
|
def leftJoin(other: Relation, on: Condition): Joined =
|
||||||
Joined(from, joins :+ Join.LeftJoin(other, on))
|
Joined(from, joins :+ Join.LeftJoin(other, on))
|
||||||
|
|
||||||
|
def leftJoin(other: TableDef, on: Condition): Joined =
|
||||||
|
leftJoin(Relation.Table(other), on)
|
||||||
}
|
}
|
||||||
|
|
||||||
case class SubSelect(sel: Select, name: String) extends FromExpr {
|
sealed trait Relation
|
||||||
def as(name: String): SubSelect =
|
object Relation {
|
||||||
copy(name = name)
|
final case class Table(table: TableDef) extends Relation
|
||||||
|
final case class SubSelect(select: Select, alias: String) extends Relation {
|
||||||
|
def as(a: String): SubSelect =
|
||||||
|
copy(alias = a)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sealed trait Join
|
||||||
|
object Join {
|
||||||
|
final case class InnerJoin(table: Relation, cond: Condition) extends Join
|
||||||
|
final case class LeftJoin(table: Relation, cond: Condition) extends Join
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
package docspell.store.qb
|
|
||||||
|
|
||||||
sealed trait Join
|
|
||||||
|
|
||||||
object Join {
|
|
||||||
|
|
||||||
case class InnerJoin(table: TableDef, cond: Condition) extends Join
|
|
||||||
|
|
||||||
case class LeftJoin(table: TableDef, cond: Condition) extends Join
|
|
||||||
}
|
|
@ -86,6 +86,11 @@ object Select {
|
|||||||
copy(projection = projection.append(e))
|
copy(projection = projection.append(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case class RawSelect(fragment: Fragment) extends Select {
|
||||||
|
def appendSelect(e: SelectExpr): RawSelect =
|
||||||
|
sys.error("RawSelect doesn't support appending select expressions")
|
||||||
|
}
|
||||||
|
|
||||||
case class Union(q: Select, qs: Vector[Select]) extends Select {
|
case class Union(q: Select, qs: Vector[Select]) extends Select {
|
||||||
def appendSelect(e: SelectExpr): Union =
|
def appendSelect(e: SelectExpr): Union =
|
||||||
copy(q = q.appendSelect(e))
|
copy(q = q.appendSelect(e))
|
||||||
|
@ -9,15 +9,12 @@ object FromExprBuilder {
|
|||||||
|
|
||||||
def build(expr: FromExpr): Fragment =
|
def build(expr: FromExpr): Fragment =
|
||||||
expr match {
|
expr match {
|
||||||
case FromExpr.From(table) =>
|
case FromExpr.From(relation) =>
|
||||||
fr" FROM" ++ buildTable(table)
|
fr" FROM" ++ buildRelation(relation)
|
||||||
|
|
||||||
case FromExpr.Joined(from, joins) =>
|
case FromExpr.Joined(from, joins) =>
|
||||||
build(from) ++
|
build(from) ++
|
||||||
joins.map(buildJoin).foldLeft(Fragment.empty)(_ ++ _)
|
joins.map(buildJoin).foldLeft(Fragment.empty)(_ ++ _)
|
||||||
|
|
||||||
case FromExpr.SubSelect(sel, name) =>
|
|
||||||
sql" FROM (" ++ SelectBuilder(sel) ++ fr") AS" ++ Fragment.const(name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def buildTable(table: TableDef): Fragment =
|
def buildTable(table: TableDef): Fragment =
|
||||||
@ -25,15 +22,24 @@ object FromExprBuilder {
|
|||||||
.map(a => Fragment.const0(a))
|
.map(a => Fragment.const0(a))
|
||||||
.getOrElse(Fragment.empty)
|
.getOrElse(Fragment.empty)
|
||||||
|
|
||||||
def buildJoin(join: Join): Fragment =
|
def buildRelation(rel: FromExpr.Relation): Fragment =
|
||||||
join match {
|
rel match {
|
||||||
case Join.InnerJoin(table, cond) =>
|
case FromExpr.Relation.Table(table) =>
|
||||||
val c = fr" ON" ++ ConditionBuilder.build(cond)
|
buildTable(table)
|
||||||
fr" INNER JOIN" ++ buildTable(table) ++ c
|
|
||||||
|
|
||||||
case Join.LeftJoin(table, cond) =>
|
case FromExpr.Relation.SubSelect(sel, alias) =>
|
||||||
|
sql" (" ++ SelectBuilder(sel) ++ fr") AS" ++ Fragment.const(alias)
|
||||||
|
}
|
||||||
|
|
||||||
|
def buildJoin(join: FromExpr.Join): Fragment =
|
||||||
|
join match {
|
||||||
|
case FromExpr.Join.InnerJoin(table, cond) =>
|
||||||
val c = fr" ON" ++ ConditionBuilder.build(cond)
|
val c = fr" ON" ++ ConditionBuilder.build(cond)
|
||||||
fr" LEFT JOIN" ++ buildTable(table) ++ c
|
fr" INNER JOIN" ++ buildRelation(table) ++ c
|
||||||
|
|
||||||
|
case FromExpr.Join.LeftJoin(table, cond) =>
|
||||||
|
val c = fr" ON" ++ ConditionBuilder.build(cond)
|
||||||
|
fr" LEFT JOIN" ++ buildRelation(table) ++ c
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,9 @@ object SelectBuilder {
|
|||||||
val sel = if (sq.distinctFlag) fr"SELECT DISTINCT" else fr"SELECT"
|
val sel = if (sq.distinctFlag) fr"SELECT DISTINCT" else fr"SELECT"
|
||||||
sel ++ buildSimple(sq)
|
sel ++ buildSimple(sq)
|
||||||
|
|
||||||
|
case Select.RawSelect(f) =>
|
||||||
|
f
|
||||||
|
|
||||||
case Select.Union(q, qs) =>
|
case Select.Union(q, qs) =>
|
||||||
qs.prepended(q).map(build).reduce(_ ++ union ++ _)
|
qs.prepended(q).map(build).reduce(_ ++ union ++ _)
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ object QJob {
|
|||||||
|
|
||||||
val gcol = Column[String]("g", TableDef(""))
|
val gcol = Column[String]("g", TableDef(""))
|
||||||
val groups =
|
val groups =
|
||||||
Select(select(gcol), fromSubSelect(union(sql1, sql2)).as("t0"), gcol.isNull.negate)
|
Select(select(gcol), from(union(sql1, sql2), "t0"), gcol.isNull.negate)
|
||||||
|
|
||||||
// either 0, one or two results, but may be empty if RJob table is empty
|
// either 0, one or two results, but may be empty if RJob table is empty
|
||||||
groups.build.query[Ident].to[List].map(_.headOption)
|
groups.build.query[Ident].to[List].map(_.headOption)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user