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

View File

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