Convert equipment record

This commit is contained in:
Eike Kettner 2020-12-08 22:43:17 +01:00
parent adee496b77
commit c5c7f7ed3b
4 changed files with 127 additions and 61 deletions

View File

@ -1,3 +1,9 @@
package docspell.store.impl
object Implicits extends DoobieMeta with DoobieSyntax
object Implicits extends DoobieMeta with DoobieSyntax {
implicit final class LegacySyntax(col: docspell.store.qb.Column[_]) {
def oldColumn: Column =
Column(col.name)
}
}

View File

@ -26,10 +26,28 @@ trait DSL extends DoobieMeta {
DBFunction.Count(c, "cn")
def and(c: Condition, cs: Condition*): Condition =
Condition.And(c, cs.toVector)
c match {
case Condition.And(head, tail) =>
Condition.And(head, tail ++ (c +: cs.toVector))
case _ =>
Condition.And(c, cs.toVector)
}
def or(c: Condition, cs: Condition*): Condition =
Condition.Or(c, cs.toVector)
c match {
case Condition.Or(head, tail) =>
Condition.Or(head, tail ++ (c +: cs.toVector))
case _ =>
Condition.Or(c, cs.toVector)
}
def not(c: Condition): Condition =
c match {
case Condition.Not(el) =>
el
case _ =>
Condition.Not(c)
}
def where(c: Condition, cs: Condition*): Condition =
and(c, cs: _*)
@ -71,7 +89,27 @@ trait DSL extends DoobieMeta {
def ===(other: Column[A]): Condition =
Condition.CompareCol(col, Operator.Eq, other)
}
implicit final class ConditionOps(c: Condition) {
def &&(other: Condition): Condition =
and(c, other)
def &&?(other: Option[Condition]): Condition =
other.map(ce => &&(ce)).getOrElse(c)
def ||(other: Condition): Condition =
or(c, other)
def ||?(other: Option[Condition]): Condition =
other.map(ce => ||(ce)).getOrElse(c)
def negate: Condition =
not(c)
def unary_! : Condition =
not(c)
}
}

View File

@ -87,13 +87,14 @@ object QItem {
}
def findItem(id: Ident): ConnectionIO[Option[ItemData]] = {
val IC = RItem.Columns.all.map(_.prefix("i"))
val OC = ROrganization.Columns.all.map(_.prefix("o"))
val P0C = RPerson.Columns.all.map(_.prefix("p0"))
val P1C = RPerson.Columns.all.map(_.prefix("p1"))
val EC = REquipment.Columns.all.map(_.prefix("e"))
val ICC = List(RItem.Columns.id, RItem.Columns.name).map(_.prefix("ref"))
val FC = List(RFolder.Columns.id, RFolder.Columns.name).map(_.prefix("f"))
val equip = REquipment.as("e")
val IC = RItem.Columns.all.map(_.prefix("i"))
val OC = ROrganization.Columns.all.map(_.prefix("o"))
val P0C = RPerson.Columns.all.map(_.prefix("p0"))
val P1C = RPerson.Columns.all.map(_.prefix("p1"))
val EC = equip.all.map(_.oldColumn).map(_.prefix("e"))
val ICC = List(RItem.Columns.id, RItem.Columns.name).map(_.prefix("ref"))
val FC = List(RFolder.Columns.id, RFolder.Columns.name).map(_.prefix("f"))
val cq =
selectSimple(
@ -110,9 +111,11 @@ object QItem {
fr"LEFT JOIN" ++ RPerson.table ++ fr"p1 ON" ++ RItem.Columns.concPerson
.prefix("i")
.is(RPerson.Columns.pid.prefix("p1")) ++
fr"LEFT JOIN" ++ REquipment.table ++ fr"e ON" ++ RItem.Columns.concEquipment
fr"LEFT JOIN" ++ Fragment.const(
equip.tableName
) ++ fr"e ON" ++ RItem.Columns.concEquipment
.prefix("i")
.is(REquipment.Columns.eid.prefix("e")) ++
.is(equip.eid.oldColumn.prefix("e")) ++
fr"LEFT JOIN" ++ RItem.table ++ fr"ref ON" ++ RItem.Columns.inReplyTo
.prefix("i")
.is(RItem.Columns.id.prefix("ref")) ++
@ -305,16 +308,16 @@ object QItem {
moreCols: Seq[Fragment],
ctes: (String, Fragment)*
): Fragment = {
val equip = REquipment.as("e1")
val IC = RItem.Columns
val AC = RAttachment.Columns
val PC = RPerson.Columns
val OC = ROrganization.Columns
val EC = REquipment.Columns
val FC = RFolder.Columns
val itemCols = IC.all
val personCols = List(PC.pid, PC.name)
val orgCols = List(OC.oid, OC.name)
val equipCols = List(EC.eid, EC.name)
val equipCols = List(equip.eid.oldColumn, equip.name.oldColumn)
val folderCols = List(FC.id, FC.name)
val cvItem = RCustomFieldValue.Columns.itemId.prefix("cv")
@ -335,8 +338,8 @@ object QItem {
PC.name.prefix("p0").f,
PC.pid.prefix("p1").f,
PC.name.prefix("p1").f,
EC.eid.prefix("e1").f,
EC.name.prefix("e1").f,
equip.eid.oldColumn.prefix("e1").f,
equip.name.oldColumn.prefix("e1").f,
FC.id.prefix("f1").f,
FC.name.prefix("f1").f,
// sql uses 1 for first character
@ -357,7 +360,11 @@ object QItem {
val withOrgs =
selectSimple(orgCols, ROrganization.table, OC.cid.is(q.account.collective))
val withEquips =
selectSimple(equipCols, REquipment.table, EC.cid.is(q.account.collective))
selectSimple(
equipCols,
Fragment.const(equip.tableName),
equip.cid.oldColumn.is(q.account.collective)
)
val withFolder =
selectSimple(folderCols, RFolder.table, FC.collective.is(q.account.collective))
val withAttach = fr"SELECT COUNT(" ++ AC.id.f ++ fr") as num, " ++ AC.itemId.f ++
@ -384,7 +391,7 @@ object QItem {
fr"LEFT JOIN persons p1 ON" ++ IC.concPerson.prefix("i").is(PC.pid.prefix("p1")) ++
fr"LEFT JOIN equips e1 ON" ++ IC.concEquipment
.prefix("i")
.is(EC.eid.prefix("e1")) ++
.is(equip.eid.oldColumn.prefix("e1")) ++
fr"LEFT JOIN folders f1 ON" ++ IC.folder.prefix("i").is(FC.id.prefix("f1")) ++
(if (q.customValues.isEmpty) Fragment.empty
else
@ -396,10 +403,10 @@ object QItem {
maxNoteLen: Int,
batch: Batch
): Stream[ConnectionIO, ListItem] = {
val IC = RItem.Columns
val PC = RPerson.Columns
val OC = ROrganization.Columns
val EC = REquipment.Columns
val equip = REquipment.as("e1")
val IC = RItem.Columns
val PC = RPerson.Columns
val OC = ROrganization.Columns
// inclusive tags are AND-ed
val tagSelectsIncl = q.tagsInclude
@ -432,7 +439,7 @@ object QItem {
OC.name.prefix("o0").lowerLike(n),
PC.name.prefix("p0").lowerLike(n),
PC.name.prefix("p1").lowerLike(n),
EC.name.prefix("e1").lowerLike(n),
equip.name.oldColumn.prefix("e1").lowerLike(n),
IC.name.prefix("i").lowerLike(n),
IC.notes.prefix("i").lowerLike(n)
)
@ -441,7 +448,7 @@ object QItem {
RPerson.Columns.pid.prefix("p0").isOrDiscard(q.corrPerson),
ROrganization.Columns.oid.prefix("o0").isOrDiscard(q.corrOrg),
RPerson.Columns.pid.prefix("p1").isOrDiscard(q.concPerson),
REquipment.Columns.eid.prefix("e1").isOrDiscard(q.concEquip),
equip.eid.oldColumn.prefix("e1").isOrDiscard(q.concEquip),
RFolder.Columns.id.prefix("f1").isOrDiscard(q.folder),
if (q.tagsInclude.isEmpty && q.tagCategoryIncl.isEmpty) Fragment.empty
else

View File

@ -1,8 +1,8 @@
package docspell.store.records
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb._
import doobie._
import doobie.implicits._
@ -16,70 +16,85 @@ case class REquipment(
) {}
object REquipment {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "equipment"
val table = fr"equipment"
object Columns {
val eid = Column("eid")
val cid = Column("cid")
val name = Column("name")
val created = Column("created")
val updated = Column("updated")
val eid = Column[Ident]("eid", this)
val cid = Column[Ident]("cid", this)
val name = Column[String]("name", this)
val created = Column[Timestamp]("created", this)
val updated = Column[Timestamp]("updated", this)
val all = List(eid, cid, name, created, updated)
}
import Columns._
def as(alias: String): Table =
Table(Some(alias))
def insert(v: REquipment): ConnectionIO[Int] = {
val sql =
insertRow(table, all, fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated}")
sql.update.run
val t = Table(None)
DML
.insert(
t,
t.all,
fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated}"
)
.update
.run
}
def update(v: REquipment): ConnectionIO[Int] = {
def sql(now: Timestamp) =
updateRow(
table,
and(eid.is(v.eid), cid.is(v.cid)),
commas(
cid.setTo(v.cid),
name.setTo(v.name),
updated.setTo(now)
)
)
val t = Table(None)
for {
now <- Timestamp.current[ConnectionIO]
n <- sql(now).update.run
n <- DML
.update(
t,
where(t.eid === v.eid, t.cid === v.cid),
DML.set(
t.cid.setTo(v.cid),
t.name.setTo(v.name),
t.updated.setTo(now)
)
)
} yield n
}
def existsByName(coll: Ident, ename: String): ConnectionIO[Boolean] = {
val sql = selectCount(eid, table, and(cid.is(coll), name.is(ename)))
val t = Table(None)
val sql = run(select(count(t.eid)), from(t), where(t.cid === coll, t.name === ename))
sql.query[Int].unique.map(_ > 0)
}
def findById(id: Ident): ConnectionIO[Option[REquipment]] = {
val sql = selectSimple(all, table, eid.is(id))
val t = Table(None)
val sql = run(select(t.all), from(t), t.eid === id)
sql.query[REquipment].option
}
def findAll(
coll: Ident,
nameQ: Option[String],
order: Columns.type => Column
order: Table => Column[_]
): ConnectionIO[Vector[REquipment]] = {
val q = Seq(cid.is(coll)) ++ (nameQ match {
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
case None => Seq.empty
})
val sql = selectSimple(all, table, and(q)) ++ orderBy(order(Columns).f)
val t = Table(None)
val q = t.cid === coll &&? nameQ
.map(str => s"%${str.toLowerCase}%")
.map(v => t.name.like(v))
val sql = Select(select(t.all), from(t), q).orderBy(order(t)).run
sql.query[REquipment].to[Vector]
}
def findLike(coll: Ident, equipName: String): ConnectionIO[Vector[IdRef]] =
selectSimple(List(eid, name), table, and(cid.is(coll), name.lowerLike(equipName)))
def findLike(coll: Ident, equipName: String): ConnectionIO[Vector[IdRef]] = {
val t = Table(None)
run(select(List(t.eid, t.name)), from(t), t.cid === coll && t.name.like(equipName))
.query[IdRef]
.to[Vector]
}
def delete(id: Ident, coll: Ident): ConnectionIO[Int] =
deleteFrom(table, and(eid.is(id), cid.is(coll))).update.run
def delete(id: Ident, coll: Ident): ConnectionIO[Int] = {
val t = Table(None)
DML.delete(t, t.eid === id && t.cid === coll).update.run
}
}