mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-04-13 01:39:33 +00:00
Extend query builder allowing more conditions
Before only a column or a dbfunction could be used in a condition. It is now allowed for all `SelectExpr`.
This commit is contained in:
parent
b514b85f39
commit
e681ffa96f
@ -15,7 +15,7 @@ object Condition {
|
|||||||
val P: Put[A]
|
val P: Put[A]
|
||||||
) extends Condition
|
) extends Condition
|
||||||
|
|
||||||
case class CompareFVal[A](dbf: DBFunction, op: Operator, value: A)(implicit
|
case class CompareFVal[A](sel: SelectExpr, op: Operator, value: A)(implicit
|
||||||
val P: Put[A]
|
val P: Put[A]
|
||||||
) extends Condition
|
) extends Condition
|
||||||
|
|
||||||
@ -23,11 +23,11 @@ object Condition {
|
|||||||
extends Condition
|
extends Condition
|
||||||
|
|
||||||
case class InSubSelect[A](col: Column[A], subSelect: Select) extends Condition
|
case class InSubSelect[A](col: Column[A], subSelect: Select) extends Condition
|
||||||
case class InValues[A](col: Column[A], values: NonEmptyList[A], lower: Boolean)(implicit
|
case class InValues[A](sel: SelectExpr, values: NonEmptyList[A], lower: Boolean)(
|
||||||
val P: Put[A]
|
implicit val P: Put[A]
|
||||||
) extends Condition
|
) extends Condition
|
||||||
|
|
||||||
case class IsNull(col: Column[_]) extends Condition
|
case class IsNull(sel: SelectExpr) extends Condition
|
||||||
|
|
||||||
case class And(inner: NonEmptyList[Condition]) extends Condition {
|
case class And(inner: NonEmptyList[Condition]) extends Condition {
|
||||||
def append(other: Condition): And =
|
def append(other: Condition): And =
|
||||||
|
@ -207,22 +207,22 @@ trait DSL extends DoobieMeta {
|
|||||||
in(subsel).negate
|
in(subsel).negate
|
||||||
|
|
||||||
def in(values: Nel[A])(implicit P: Put[A]): Condition =
|
def in(values: Nel[A])(implicit P: Put[A]): Condition =
|
||||||
Condition.InValues(col, values, false)
|
Condition.InValues(col.s, values, false)
|
||||||
|
|
||||||
def notIn(values: Nel[A])(implicit P: Put[A]): Condition =
|
def notIn(values: Nel[A])(implicit P: Put[A]): Condition =
|
||||||
in(values).negate
|
in(values).negate
|
||||||
|
|
||||||
def inLower(values: Nel[A])(implicit P: Put[A]): Condition =
|
def inLower(values: Nel[A])(implicit P: Put[A]): Condition =
|
||||||
Condition.InValues(col, values, true)
|
Condition.InValues(col.s, values, true)
|
||||||
|
|
||||||
def notInLower(values: Nel[A])(implicit P: Put[A]): Condition =
|
def notInLower(values: Nel[A])(implicit P: Put[A]): Condition =
|
||||||
Condition.InValues(col, values, true).negate
|
Condition.InValues(col.s, values, true).negate
|
||||||
|
|
||||||
def isNull: Condition =
|
def isNull: Condition =
|
||||||
Condition.IsNull(col)
|
Condition.IsNull(col.s)
|
||||||
|
|
||||||
def isNotNull: Condition =
|
def isNotNull: Condition =
|
||||||
Condition.IsNull(col).negate
|
Condition.IsNull(col.s).negate
|
||||||
|
|
||||||
def ===(other: Column[A]): Condition =
|
def ===(other: Column[A]): Condition =
|
||||||
Condition.CompareCol(col, Operator.Eq, other)
|
Condition.CompareCol(col, Operator.Eq, other)
|
||||||
@ -267,31 +267,31 @@ trait DSL extends DoobieMeta {
|
|||||||
SelectExpr.SelectFun(dbf, Some(otherCol.name))
|
SelectExpr.SelectFun(dbf, Some(otherCol.name))
|
||||||
|
|
||||||
def ===[A](value: A)(implicit P: Put[A]): Condition =
|
def ===[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Eq, value)
|
Condition.CompareFVal(dbf.s, Operator.Eq, value)
|
||||||
|
|
||||||
def ====(value: String): Condition =
|
def ====(value: String): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Eq, value)
|
Condition.CompareFVal(dbf.s, Operator.Eq, value)
|
||||||
|
|
||||||
def like[A](value: A)(implicit P: Put[A]): Condition =
|
def like[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.LowerLike, value)
|
Condition.CompareFVal(dbf.s, Operator.LowerLike, value)
|
||||||
|
|
||||||
def likes(value: String): Condition =
|
def likes(value: String): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.LowerLike, value)
|
Condition.CompareFVal(dbf.s, Operator.LowerLike, value)
|
||||||
|
|
||||||
def <=[A](value: A)(implicit P: Put[A]): Condition =
|
def <=[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Lte, value)
|
Condition.CompareFVal(dbf.s, Operator.Lte, value)
|
||||||
|
|
||||||
def >=[A](value: A)(implicit P: Put[A]): Condition =
|
def >=[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Gte, value)
|
Condition.CompareFVal(dbf.s, Operator.Gte, value)
|
||||||
|
|
||||||
def >[A](value: A)(implicit P: Put[A]): Condition =
|
def >[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Gt, value)
|
Condition.CompareFVal(dbf.s, Operator.Gt, value)
|
||||||
|
|
||||||
def <[A](value: A)(implicit P: Put[A]): Condition =
|
def <[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Lt, value)
|
Condition.CompareFVal(dbf.s, Operator.Lt, value)
|
||||||
|
|
||||||
def <>[A](value: A)(implicit P: Put[A]): Condition =
|
def <>[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
Condition.CompareFVal(dbf, Operator.Neq, value)
|
Condition.CompareFVal(dbf.s, Operator.Neq, value)
|
||||||
|
|
||||||
def -[A](value: A)(implicit P: Put[A]): DBFunction =
|
def -[A](value: A)(implicit P: Put[A]): DBFunction =
|
||||||
DBFunction.Calc(
|
DBFunction.Calc(
|
||||||
@ -300,6 +300,35 @@ trait DSL extends DoobieMeta {
|
|||||||
SelectExpr.SelectConstant(value, None)
|
SelectExpr.SelectConstant(value, None)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
implicit final class SelectExprOps(sel: SelectExpr) {
|
||||||
|
def isNull: Condition =
|
||||||
|
Condition.IsNull(sel)
|
||||||
|
|
||||||
|
def isNotNull: Condition =
|
||||||
|
Condition.IsNull(sel).negate
|
||||||
|
|
||||||
|
def ===[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Eq, value)
|
||||||
|
|
||||||
|
def <=[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Lte, value)
|
||||||
|
|
||||||
|
def >=[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Gte, value)
|
||||||
|
|
||||||
|
def >[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Gt, value)
|
||||||
|
|
||||||
|
def <[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Lt, value)
|
||||||
|
|
||||||
|
def <>[A](value: A)(implicit P: Put[A]): Condition =
|
||||||
|
Condition.CompareFVal(sel, Operator.Neq, value)
|
||||||
|
|
||||||
|
def in[A](values: Nel[A])(implicit P: Put[A]): Condition =
|
||||||
|
Condition.InValues(sel, values, false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object DSL extends DSL {
|
object DSL extends DSL {
|
||||||
|
@ -92,7 +92,7 @@ object ItemQueryGenerator {
|
|||||||
val dt = dateToTimestamp(today)(value)
|
val dt = dateToTimestamp(today)(value)
|
||||||
val col = timestampColumn(tables)(attr)
|
val col = timestampColumn(tables)(attr)
|
||||||
val noLikeOp = if (op == Operator.Like) Operator.Eq else op
|
val noLikeOp = if (op == Operator.Like) Operator.Eq else op
|
||||||
Condition.CompareVal(col, makeOp(noLikeOp), dt)
|
Condition.CompareFVal(col, makeOp(noLikeOp), dt)
|
||||||
|
|
||||||
case Expr.SimpleExpr(op, Property.IntProperty(attr, value)) =>
|
case Expr.SimpleExpr(op, Property.IntProperty(attr, value)) =>
|
||||||
val col = intColumn(tables)(attr)
|
val col = intColumn(tables)(attr)
|
||||||
@ -203,22 +203,22 @@ object ItemQueryGenerator {
|
|||||||
today
|
today
|
||||||
}
|
}
|
||||||
|
|
||||||
private def anyColumn(tables: Tables)(attr: Attr): Column[_] =
|
private def anyColumn(tables: Tables)(attr: Attr): SelectExpr =
|
||||||
attr match {
|
attr match {
|
||||||
case s: Attr.StringAttr =>
|
case s: Attr.StringAttr =>
|
||||||
stringColumn(tables)(s)
|
stringColumn(tables)(s).s
|
||||||
case t: Attr.DateAttr =>
|
case t: Attr.DateAttr =>
|
||||||
timestampColumn(tables)(t)
|
timestampColumn(tables)(t)
|
||||||
case n: Attr.IntAttr =>
|
case n: Attr.IntAttr =>
|
||||||
intColumn(tables)(n)
|
intColumn(tables)(n).s
|
||||||
}
|
}
|
||||||
|
|
||||||
private def timestampColumn(tables: Tables)(attr: Attr.DateAttr) =
|
private def timestampColumn(tables: Tables)(attr: Attr.DateAttr): SelectExpr =
|
||||||
attr match {
|
attr match {
|
||||||
case Attr.Date =>
|
case Attr.Date =>
|
||||||
tables.item.itemDate
|
coalesce(tables.item.itemDate.s, tables.item.created.s).s
|
||||||
case Attr.DueDate =>
|
case Attr.DueDate =>
|
||||||
tables.item.dueDate
|
tables.item.dueDate.s
|
||||||
}
|
}
|
||||||
|
|
||||||
private def stringColumn(tables: Tables)(attr: Attr.StringAttr): Column[String] =
|
private def stringColumn(tables: Tables)(attr: Attr.StringAttr): Column[String] =
|
||||||
@ -283,7 +283,7 @@ object ItemQueryGenerator {
|
|||||||
|
|
||||||
value.toDoubleOption
|
value.toDoubleOption
|
||||||
.map { n =>
|
.map { n =>
|
||||||
val numericCmp = Condition.CompareFVal(castNumeric(cfv.value.s), op, n)
|
val numericCmp = Condition.CompareFVal(castNumeric(cfv.value.s).s, op, n)
|
||||||
val fieldIsNumeric =
|
val fieldIsNumeric =
|
||||||
cf.ftype === CustomFieldType.Numeric || cf.ftype === CustomFieldType.Money
|
cf.ftype === CustomFieldType.Numeric || cf.ftype === CustomFieldType.Money
|
||||||
val fieldNotNumeric =
|
val fieldNotNumeric =
|
||||||
|
@ -85,7 +85,7 @@ object ConditionBuilder {
|
|||||||
case Operator.LowerEq =>
|
case Operator.LowerEq =>
|
||||||
lower(dbf)
|
lower(dbf)
|
||||||
case _ =>
|
case _ =>
|
||||||
DBFunctionBuilder.build(dbf)
|
SelectExprBuilder.build(dbf)
|
||||||
}
|
}
|
||||||
dbfFrag ++ opFrag ++ valFrag
|
dbfFrag ++ opFrag ++ valFrag
|
||||||
|
|
||||||
@ -105,13 +105,13 @@ object ConditionBuilder {
|
|||||||
SelectExprBuilder.column(col) ++ sql" IN (" ++ sub ++ parenClose
|
SelectExprBuilder.column(col) ++ sql" IN (" ++ sub ++ parenClose
|
||||||
|
|
||||||
case c @ Condition.InValues(col, values, toLower) =>
|
case c @ Condition.InValues(col, values, toLower) =>
|
||||||
val cfrag = if (toLower) lower(col) else SelectExprBuilder.column(col)
|
val cfrag = if (toLower) lower(col) else SelectExprBuilder.build(col)
|
||||||
cfrag ++ sql" IN (" ++ values.toList
|
cfrag ++ sql" IN (" ++ values.toList
|
||||||
.map(a => buildValue(a)(c.P))
|
.map(a => buildValue(a)(c.P))
|
||||||
.reduce(_ ++ comma ++ _) ++ parenClose
|
.reduce(_ ++ comma ++ _) ++ parenClose
|
||||||
|
|
||||||
case Condition.IsNull(col) =>
|
case Condition.IsNull(col) =>
|
||||||
SelectExprBuilder.column(col) ++ fr" is null"
|
SelectExprBuilder.build(col) ++ fr" is null"
|
||||||
|
|
||||||
case Condition.And(ands) =>
|
case Condition.And(ands) =>
|
||||||
val inner = ands.map(build).reduceLeft(_ ++ and ++ _)
|
val inner = ands.map(build).reduceLeft(_ ++ and ++ _)
|
||||||
@ -124,7 +124,7 @@ object ConditionBuilder {
|
|||||||
else parenOpen ++ inner ++ parenClose
|
else parenOpen ++ inner ++ parenClose
|
||||||
|
|
||||||
case Condition.Not(Condition.IsNull(col)) =>
|
case Condition.Not(Condition.IsNull(col)) =>
|
||||||
SelectExprBuilder.column(col) ++ fr" is not null"
|
SelectExprBuilder.build(col) ++ fr" is not null"
|
||||||
|
|
||||||
case Condition.Not(c) =>
|
case Condition.Not(c) =>
|
||||||
fr"NOT" ++ build(c)
|
fr"NOT" ++ build(c)
|
||||||
@ -159,6 +159,9 @@ object ConditionBuilder {
|
|||||||
def buildOptValue[A: Put](v: Option[A]): Fragment =
|
def buildOptValue[A: Put](v: Option[A]): Fragment =
|
||||||
fr"$v"
|
fr"$v"
|
||||||
|
|
||||||
|
def lower(sel: SelectExpr): Fragment =
|
||||||
|
Fragment.const0("LOWER(") ++ SelectExprBuilder.build(sel) ++ parenClose
|
||||||
|
|
||||||
def lower(col: Column[_]): Fragment =
|
def lower(col: Column[_]): Fragment =
|
||||||
Fragment.const0("LOWER(") ++ SelectExprBuilder.column(col) ++ parenClose
|
Fragment.const0("LOWER(") ++ SelectExprBuilder.column(col) ++ parenClose
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user