Convert more records

This commit is contained in:
Eike Kettner 2020-12-13 13:35:40 +01:00
parent 613696539f
commit fd6d09587d
15 changed files with 996 additions and 675 deletions

View File

@ -74,6 +74,10 @@ object DML {
case Setter.Increment(column, amount) =>
val colFrag = SelectExprBuilder.columnNoPrefix(column)
colFrag ++ fr" =" ++ colFrag ++ fr" + $amount"
case Setter.Decrement(column, amount) =>
val colFrag = SelectExprBuilder.columnNoPrefix(column)
colFrag ++ fr" =" ++ colFrag ++ fr" - $amount"
}
def set(s: Setter[_], more: Setter[_]*): Nel[Setter[_]] =

View File

@ -127,6 +127,9 @@ trait DSL extends DoobieMeta {
def increment(amount: Int): Setter[A] =
Setter.Increment(col, amount)
def decrement(amount: Int): Setter[A] =
Setter.Decrement(col, amount)
def asc: OrderBy =
OrderBy(SelectExpr.SelectColumn(col, None), OrderBy.OrderType.Asc)
@ -177,6 +180,9 @@ trait DSL extends DoobieMeta {
def ===(other: Column[A]): Condition =
Condition.CompareCol(col, Operator.Eq, other)
def <>(other: Column[A]): Condition =
Condition.CompareCol(col, Operator.Neq, other)
}
implicit final class ConditionOps(c: Condition) {

View File

@ -13,5 +13,6 @@ object Setter {
extends Setter[A]
case class Increment[A](column: Column[A], amount: Int) extends Setter[A]
case class Decrement[A](column: Column[A], amount: Int) extends Setter[A]
}

View File

@ -180,14 +180,17 @@ object QAttachment {
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val iFolder = RItem.Columns.folder.prefix("i")
val cId = RCollective.Columns.id.prefix("c")
val cLang = RCollective.Columns.language.prefix("c")
val c = RCollective.as("c")
val cId = c.id.column
val cLang = c.language.column
val cols = Seq(aId, aItem, iColl, iFolder, cLang, aName, mContent)
val from = RAttachment.table ++ fr"a INNER JOIN" ++
RAttachmentMeta.table ++ fr"m ON" ++ aId.is(mId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem) ++
fr"INNER JOIN" ++ RCollective.table ++ fr"c ON" ++ cId.is(iColl)
fr"INNER JOIN" ++ Fragment.const(RCollective.T.tableName) ++ fr"c ON" ++ cId.is(
iColl
)
val where = coll.map(cid => iColl.is(cid)).getOrElse(Fragment.empty)

View File

@ -633,27 +633,31 @@ object QItem {
limit: Option[Int],
states: Set[ItemState]
): Fragment = {
val IC = RItem.Columns.all.map(_.prefix("i"))
val aItem = RAttachment.Columns.itemId.prefix("a")
val aId = RAttachment.Columns.id.prefix("a")
val aFileId = RAttachment.Columns.fileId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iState = RItem.Columns.state.prefix("i")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFileId = RAttachmentSource.Columns.fileId.prefix("s")
val rId = RAttachmentArchive.Columns.id.prefix("r")
val rFileId = RAttachmentArchive.Columns.fileId.prefix("r")
val m1Id = RFileMeta.Columns.id.prefix("m1")
val m2Id = RFileMeta.Columns.id.prefix("m2")
val m3Id = RFileMeta.Columns.id.prefix("m3")
val IC = RItem.Columns.all.map(_.prefix("i"))
val aItem = RAttachment.Columns.itemId.prefix("a")
val aId = RAttachment.Columns.id.prefix("a")
val aFileId = RAttachment.Columns.fileId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iState = RItem.Columns.state.prefix("i")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFileId = RAttachmentSource.Columns.fileId.prefix("s")
val rId = RAttachmentArchive.Columns.id.prefix("r")
val rFileId = RAttachmentArchive.Columns.fileId.prefix("r")
val m1 = RFileMeta.as("m1")
val m2 = RFileMeta.as("m2")
val m3 = RFileMeta.as("m3")
val m1Id = m1.id.column
val m2Id = m2.id.column
val m3Id = m3.id.column
val filemetaTable = Fragment.const(RFileMeta.T.tableName)
val from =
RItem.table ++ fr"i INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ aItem.is(iId) ++
fr"INNER JOIN" ++ RAttachmentSource.table ++ fr"s ON" ++ aId.is(sId) ++
fr"INNER JOIN" ++ RFileMeta.table ++ fr"m1 ON" ++ m1Id.is(aFileId) ++
fr"INNER JOIN" ++ RFileMeta.table ++ fr"m2 ON" ++ m2Id.is(sFileId) ++
fr"INNER JOIN" ++ filemetaTable ++ fr"m1 ON" ++ m1Id.is(aFileId) ++
fr"INNER JOIN" ++ filemetaTable ++ fr"m2 ON" ++ m2Id.is(sFileId) ++
fr"LEFT OUTER JOIN" ++ RAttachmentArchive.table ++ fr"r ON" ++ aId.is(rId) ++
fr"LEFT OUTER JOIN" ++ RFileMeta.table ++ fr"m3 ON" ++ m3Id.is(rFileId)
fr"LEFT OUTER JOIN" ++ filemetaTable ++ fr"m3 ON" ++ m3Id.is(rFileId)
val fileCond =
or(m1Id.isIn(fileMetaIds), m2Id.isIn(fileMetaIds), m3Id.isIn(fileMetaIds))
@ -691,30 +695,33 @@ object QItem {
}
def findByChecksum(checksum: String, collective: Ident): ConnectionIO[Vector[RItem]] = {
val IC = RItem.Columns.all.map(_.prefix("i"))
val aItem = RAttachment.Columns.itemId.prefix("a")
val aId = RAttachment.Columns.id.prefix("a")
val aFileId = RAttachment.Columns.fileId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFileId = RAttachmentSource.Columns.fileId.prefix("s")
val rId = RAttachmentArchive.Columns.id.prefix("r")
val rFileId = RAttachmentArchive.Columns.fileId.prefix("r")
val m1Id = RFileMeta.Columns.id.prefix("m1")
val m2Id = RFileMeta.Columns.id.prefix("m2")
val m3Id = RFileMeta.Columns.id.prefix("m3")
val m1Checksum = RFileMeta.Columns.checksum.prefix("m1")
val m2Checksum = RFileMeta.Columns.checksum.prefix("m2")
val m3Checksum = RFileMeta.Columns.checksum.prefix("m3")
val IC = RItem.Columns.all.map(_.prefix("i"))
val aItem = RAttachment.Columns.itemId.prefix("a")
val aId = RAttachment.Columns.id.prefix("a")
val aFileId = RAttachment.Columns.fileId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFileId = RAttachmentSource.Columns.fileId.prefix("s")
val rId = RAttachmentArchive.Columns.id.prefix("r")
val rFileId = RAttachmentArchive.Columns.fileId.prefix("r")
val m1 = RFileMeta.as("m1")
val m2 = RFileMeta.as("m2")
val m3 = RFileMeta.as("m3")
val m1Id = m1.id.column
val m2Id = m2.id.column
val m3Id = m3.id.column
val m1Checksum = m1.checksum.column
val m2Checksum = m2.checksum.column
val m3Checksum = m3.checksum.column
val filemetaTable = Fragment.const(RFileMeta.T.tableName)
val from =
RItem.table ++ fr"i INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ aItem.is(iId) ++
fr"INNER JOIN" ++ RAttachmentSource.table ++ fr"s ON" ++ aId.is(sId) ++
fr"INNER JOIN" ++ RFileMeta.table ++ fr"m1 ON" ++ m1Id.is(aFileId) ++
fr"INNER JOIN" ++ RFileMeta.table ++ fr"m2 ON" ++ m2Id.is(sFileId) ++
fr"INNER JOIN" ++ filemetaTable ++ fr"m1 ON" ++ m1Id.is(aFileId) ++
fr"INNER JOIN" ++ filemetaTable ++ fr"m2 ON" ++ m2Id.is(sFileId) ++
fr"LEFT OUTER JOIN" ++ RAttachmentArchive.table ++ fr"r ON" ++ aId.is(rId) ++
fr"LEFT OUTER JOIN" ++ RFileMeta.table ++ fr"m3 ON" ++ m3Id.is(rFileId)
fr"LEFT OUTER JOIN" ++ filemetaTable ++ fr"m3 ON" ++ m3Id.is(rFileId)
selectSimple(
IC,

View File

@ -3,8 +3,8 @@ package docspell.store.queries
import cats.data.OptionT
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.records.RCollective.{Columns => CC}
import docspell.store.qb.DSL._
import docspell.store.qb._
import docspell.store.records.{RCollective, RRememberMe, RUser}
import doobie._
@ -22,20 +22,14 @@ object QLogin {
)
def findUser(acc: AccountId): ConnectionIO[Option[Data]] = {
val user = RUser.as("u")
val ucid = user.cid.column
val login = user.login.column
val pass = user.password.column
val ustate = user.state.column
val cstate = CC.state.prefix("c")
val ccid = CC.id.prefix("c")
val sql = selectSimple(
List(ucid, login, pass, cstate, ustate),
Fragment.const(user.tableName) ++ fr"u, " ++ RCollective.table ++ fr"c",
and(ucid.is(ccid), login.is(acc.user), ucid.is(acc.collective))
)
val user = RUser.as("u")
val coll = RCollective.as("c")
val sql =
Select(
select(user.cid, user.login, user.password, coll.state, user.state),
from(user).innerJoin(coll, user.cid === coll.id),
user.login === acc.user && user.cid === acc.collective
).build
logger.trace(s"SQL : $sql")
sql.query[Data].option
}

View File

@ -5,8 +5,9 @@ import cats.implicits._
import fs2.Stream
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb.TableDef
import docspell.store.qb._
import bitpeace.FileMeta
import doobie._
@ -22,10 +23,27 @@ case class RAttachment(
) {}
object RAttachment {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "attachment"
val id = Column[Ident]("attachid", this)
val itemId = Column[Ident]("itemid", this)
val fileId = Column[Ident]("filemetaid", this)
val position = Column[Int]("position", this)
val created = Column[Timestamp]("created", this)
val name = Column[String]("name", this)
val all = NonEmptyList.of[Column[_]](id, itemId, fileId, position, created, name)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
val table = fr"attachment"
object Columns {
import docspell.store.impl._
val id = Column("attachid")
val itemId = Column("itemid")
val fileId = Column("filemetaid")
@ -34,32 +52,37 @@ object RAttachment {
val name = Column("name")
val all = List(id, itemId, fileId, position, created, name)
}
import Columns._
def insert(v: RAttachment): ConnectionIO[Int] =
insertRow(
table,
all,
DML.insert(
T,
T.all,
fr"${v.id},${v.itemId},${v.fileId.id},${v.position},${v.created},${v.name}"
).update.run
)
def decPositions(iId: Ident, lowerBound: Int, upperBound: Int): ConnectionIO[Int] =
updateRow(
table,
and(itemId.is(iId), position.isGte(lowerBound), position.isLte(upperBound)),
position.decrement(1)
).update.run
DML.update(
T,
where(
T.itemId === iId && T.position >= lowerBound && T.position <= upperBound
),
DML.set(T.position.decrement(1))
)
def incPositions(iId: Ident, lowerBound: Int, upperBound: Int): ConnectionIO[Int] =
updateRow(
table,
and(itemId.is(iId), position.isGte(lowerBound), position.isLte(upperBound)),
position.increment(1)
).update.run
DML.update(
T,
where(
T.itemId === iId && T.position >= lowerBound && T.position <= upperBound
),
DML.set(T.position.increment(1))
)
def nextPosition(id: Ident): ConnectionIO[Int] =
for {
max <- selectSimple(position.max, table, itemId.is(id)).query[Option[Int]].unique
max <- Select(max(T.position).s, from(T), T.itemId === id).build
.query[Option[Int]]
.unique
} yield max.map(_ + 1).getOrElse(0)
def updateFileIdAndName(
@ -67,41 +90,49 @@ object RAttachment {
fId: Ident,
fname: Option[String]
): ConnectionIO[Int] =
updateRow(
table,
id.is(attachId),
commas(fileId.setTo(fId), name.setTo(fname))
).update.run
DML.update(
T,
T.id === attachId,
DML.set(T.fileId.setTo(fId), T.name.setTo(fname))
)
def updateFileId(
attachId: Ident,
fId: Ident
): ConnectionIO[Int] =
updateRow(
table,
id.is(attachId),
fileId.setTo(fId)
).update.run
DML.update(
T,
T.id === attachId,
DML.set(T.fileId.setTo(fId))
)
def updatePosition(attachId: Ident, pos: Int): ConnectionIO[Int] =
updateRow(table, id.is(attachId), position.setTo(pos)).update.run
DML.update(T, T.id === attachId, DML.set(T.position.setTo(pos)))
def findById(attachId: Ident): ConnectionIO[Option[RAttachment]] =
selectSimple(all, table, id.is(attachId)).query[RAttachment].option
run(select(T.all), from(T), T.id === attachId).query[RAttachment].option
def findMeta(attachId: Ident): ConnectionIO[Option[FileMeta]] = {
import bitpeace.sql._
val cols = RFileMeta.Columns.all.map(_.prefix("m"))
val aId = id.prefix("a")
val aFileMeta = fileId.prefix("a")
val mId = RFileMeta.Columns.id.prefix("m")
val from =
table ++ fr"a INNER JOIN" ++ RFileMeta.table ++ fr"m ON" ++ aFileMeta.is(mId)
val cond = aId.is(attachId)
selectSimple(cols, from, cond).query[FileMeta].option
// val cols = RFileMeta.Columns.all.map(_.prefix("m"))
// val aId = id.prefix("a")
// val aFileMeta = fileId.prefix("a")
// val mId = RFileMeta.Columns.id.prefix("m")
//
// val from =
// table ++ fr"a INNER JOIN" ++ RFileMeta.table ++ fr"m ON" ++ aFileMeta.is(mId)
// val cond = aId.is(attachId)
//
// selectSimple(cols, from, cond).query[FileMeta].option
val m = RFileMeta.as("m")
val a = RAttachment.as("a")
Select(
select(m.all),
from(a)
.innerJoin(m, a.fileId === m.id),
a.id === attachId
).build.query[FileMeta].option
}
def updateName(
@ -109,7 +140,7 @@ object RAttachment {
collective: Ident,
aname: Option[String]
): ConnectionIO[Int] = {
val update = updateRow(table, id.is(attachId), name.setTo(aname)).update.run
val update = DML.update(T, T.id === attachId, DML.set(T.name.setTo(aname)))
for {
exists <- existsByIdAndCollective(attachId, collective)
n <- if (exists) update else 0.pure[ConnectionIO]
@ -119,44 +150,59 @@ object RAttachment {
def findByIdAndCollective(
attachId: Ident,
collective: Ident
): ConnectionIO[Option[RAttachment]] =
selectSimple(
all.map(_.prefix("a")),
table ++ fr"a," ++ RItem.table ++ fr"i",
and(
fr"a.itemid = i.itemid",
id.prefix("a").is(attachId),
RItem.Columns.cid.prefix("i").is(collective)
)
).query[RAttachment].option
): ConnectionIO[Option[RAttachment]] = {
val a = RAttachment.as("a")
val i = RItem.as("i")
Select(
select(a.all),
from(a).innerJoin(i, a.itemId === i.id),
a.id === attachId && i.cid === collective
).build.query[RAttachment].option
}
def findByItem(id: Ident): ConnectionIO[Vector[RAttachment]] =
selectSimple(all, table, itemId.is(id)).query[RAttachment].to[Vector]
run(select(T.all), from(T), T.itemId === id).query[RAttachment].to[Vector]
def existsByIdAndCollective(
attachId: Ident,
collective: Ident
): ConnectionIO[Boolean] = {
val aId = id.prefix("a")
val aItem = itemId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val from =
table ++ fr"a INNER JOIN" ++ RItem.table ++ fr"i ON" ++ aItem.is(iId)
val cond = and(iColl.is(collective), aId.is(attachId))
selectCount(id, from, cond).query[Int].unique.map(_ > 0)
// val aId = id.prefix("a")
// val aItem = itemId.prefix("a")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
// val from =
// table ++ fr"a INNER JOIN" ++ RItem.table ++ fr"i ON" ++ aItem.is(iId)
// val cond = and(iColl.is(collective), aId.is(attachId))
// selectCount(id, from, cond).query[Int].unique.map(_ > 0)
val a = RAttachment.as("a")
val i = RItem.as("i")
Select(
count(a.id).s,
from(a)
.innerJoin(i, a.itemId === i.id),
i.cid === collective && a.id === attachId
).build.query[Int].unique.map(_ > 0)
}
def findByItemAndCollective(
id: Ident,
coll: Ident
): ConnectionIO[Vector[RAttachment]] = {
val q = selectSimple(all.map(_.prefix("a")), table ++ fr"a", Fragment.empty) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ RItem.Columns.id
.prefix("i")
.is(itemId.prefix("a")) ++
fr"WHERE" ++ and(itemId.prefix("a").is(id), RItem.Columns.cid.prefix("i").is(coll))
q.query[RAttachment].to[Vector]
// val q = selectSimple(all.map(_.prefix("a")), table ++ fr"a", Fragment.empty) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ RItem.Columns.id
// .prefix("i")
// .is(itemId.prefix("a")) ++
// fr"WHERE" ++ and(itemId.prefix("a").is(id), RItem.Columns.cid.prefix("i").is(coll))
// q.query[RAttachment].to[Vector]
val a = RAttachment.as("a")
val i = RItem.as("i")
Select(
select(a.all),
from(a)
.innerJoin(i, i.id === a.itemId),
a.itemId === id && i.cid === coll
).build.query[RAttachment].to[Vector]
}
def findByItemCollectiveSource(
@ -165,28 +211,42 @@ object RAttachment {
fileIds: NonEmptyList[Ident]
): ConnectionIO[Vector[RAttachment]] = {
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val aItem = Columns.itemId.prefix("a")
val aId = Columns.id.prefix("a")
val aFile = Columns.fileId.prefix("a")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFile = RAttachmentSource.Columns.fileId.prefix("s")
val rId = RAttachmentArchive.Columns.id.prefix("r")
val rFile = RAttachmentArchive.Columns.fileId.prefix("r")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
// val aItem = Columns.itemId.prefix("a")
// val aId = Columns.id.prefix("a")
// val aFile = Columns.fileId.prefix("a")
// val sId = RAttachmentSource.Columns.id.prefix("s")
// val sFile = RAttachmentSource.Columns.fileId.prefix("s")
// val rId = RAttachmentArchive.Columns.id.prefix("r")
// val rFile = RAttachmentArchive.Columns.fileId.prefix("r")
//
// val from = table ++ fr"a INNER JOIN" ++
// RItem.table ++ fr"i ON" ++ iId.is(aItem) ++ fr"LEFT JOIN" ++
// RAttachmentSource.table ++ fr"s ON" ++ sId.is(aId) ++ fr"LEFT JOIN" ++
// RAttachmentArchive.table ++ fr"r ON" ++ rId.is(aId)
//
// val cond = and(
// iId.is(id),
// iColl.is(coll),
// or(aFile.isIn(fileIds), sFile.isIn(fileIds), rFile.isIn(fileIds))
// )
//
// selectSimple(all.map(_.prefix("a")), from, cond).query[RAttachment].to[Vector]
val i = RItem.as("i")
val a = RAttachment.as("a")
val s = RAttachmentSource.as("s")
val r = RAttachmentArchive.as("r")
val from = table ++ fr"a INNER JOIN" ++
RItem.table ++ fr"i ON" ++ iId.is(aItem) ++ fr"LEFT JOIN" ++
RAttachmentSource.table ++ fr"s ON" ++ sId.is(aId) ++ fr"LEFT JOIN" ++
RAttachmentArchive.table ++ fr"r ON" ++ rId.is(aId)
val cond = and(
iId.is(id),
iColl.is(coll),
or(aFile.isIn(fileIds), sFile.isIn(fileIds), rFile.isIn(fileIds))
)
selectSimple(all.map(_.prefix("a")), from, cond).query[RAttachment].to[Vector]
Select(
select(a.all),
from(a)
.innerJoin(i, i.id === a.itemId)
.leftJoin(s, s.id === a.id)
.leftJoin(r, r.id === a.id),
i.id === id && i.cid === coll &&
(a.fileId.in(fileIds) || s.fileId.in(fileIds) || r.fileId.in(fileIds))
).build.query[RAttachment].to[Vector]
}
def findByItemAndCollectiveWithMeta(
@ -195,27 +255,45 @@ object RAttachment {
): ConnectionIO[Vector[(RAttachment, FileMeta)]] = {
import bitpeace.sql._
val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
val afileMeta = fileId.prefix("a")
val aItem = itemId.prefix("a")
val mId = RFileMeta.Columns.id.prefix("m")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val from =
table ++ fr"a INNER JOIN" ++ RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ aItem.is(iId)
val cond = Seq(aItem.is(id), iColl.is(coll))
selectSimple(cols, from, and(cond)).query[(RAttachment, FileMeta)].to[Vector]
// val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
// val afileMeta = fileId.prefix("a")
// val aItem = itemId.prefix("a")
// val mId = RFileMeta.Columns.id.prefix("m")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from =
// table ++ fr"a INNER JOIN" ++ RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ aItem.is(iId)
// val cond = Seq(aItem.is(id), iColl.is(coll))
//
// selectSimple(cols, from, and(cond)).query[(RAttachment, FileMeta)].to[Vector]
val a = RAttachment.as("a")
val m = RFileMeta.as("m")
val i = RItem.as("i")
Select(
select(a.all, m.all),
from(a)
.innerJoin(m, a.fileId === m.id)
.innerJoin(i, a.itemId === i.id),
a.itemId === id && i.cid === coll
).build.query[(RAttachment, FileMeta)].to[Vector]
}
def findByItemWithMeta(id: Ident): ConnectionIO[Vector[(RAttachment, FileMeta)]] = {
import bitpeace.sql._
val q =
fr"SELECT a.*,m.* FROM" ++ table ++ fr"a, filemeta m WHERE a.filemetaid = m.id AND a.itemid = $id ORDER BY a.position ASC"
q.query[(RAttachment, FileMeta)].to[Vector]
// val q =
// fr"SELECT a.*,m.* FROM" ++ table ++ fr"a, filzemeta m
// WHERE a.filemetaid = m.id AND a.itemid = $id ORDER BY a.position ASC"
val a = RAttachment.as("a")
val m = RFileMeta.as("m")
Select(
select(a.all, m.all),
from(a)
.innerJoin(m, a.fileId === m.id),
a.itemId === id
).orderBy(a.position.asc).build.query[(RAttachment, FileMeta)].to[Vector]
}
/** Deletes the attachment and its related source and meta records.
@ -225,110 +303,159 @@ object RAttachment {
n0 <- RAttachmentMeta.delete(attachId)
n1 <- RAttachmentSource.delete(attachId)
n2 <- RAttachmentPreview.delete(attachId)
n3 <- deleteFrom(table, id.is(attachId)).update.run
n3 <- DML.delete(T, T.id === attachId)
} yield n0 + n1 + n2 + n3
def findItemId(attachId: Ident): ConnectionIO[Option[Ident]] =
selectSimple(Seq(itemId), table, id.is(attachId)).query[Ident].option
Select(T.itemId.s, from(T), T.id === attachId).build.query[Ident].option
def findAll(
coll: Option[Ident],
chunkSize: Int
): Stream[ConnectionIO, RAttachment] = {
val aItem = Columns.itemId.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val cols = all.map(_.prefix("a"))
// val aItem = Columns.itemId.prefix("a")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val cols = all.map(_.prefix("a"))
//
// coll match {
// case Some(cid) =>
// val join = table ++ fr"a INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
// val cond = iColl.is(cid)
// selectSimple(cols, join, cond)
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
// case None =>
// selectSimple(cols, table, Fragment.empty)
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
// }
val a = RAttachment.as("a")
val i = RItem.as("i")
coll match {
case Some(cid) =>
val join = table ++ fr"a INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
val cond = iColl.is(cid)
selectSimple(cols, join, cond)
.query[RAttachment]
.streamWithChunkSize(chunkSize)
Select(
select(a.all),
from(a)
.innerJoin(i, i.id === a.itemId),
i.cid === cid
).build.query[RAttachment].streamWithChunkSize(chunkSize)
case None =>
selectSimple(cols, table, Fragment.empty)
Select(select(a.all), from(a)).build
.query[RAttachment]
.streamWithChunkSize(chunkSize)
}
}
def findAllWithoutPageCount(chunkSize: Int): Stream[ConnectionIO, RAttachment] = {
val aId = Columns.id.prefix("a")
val aCreated = Columns.created.prefix("a")
val mId = RAttachmentMeta.Columns.id.prefix("m")
val mPages = RAttachmentMeta.Columns.pages.prefix("m")
val cols = all.map(_.prefix("a"))
val join = table ++ fr"a LEFT OUTER JOIN" ++
RAttachmentMeta.table ++ fr"m ON" ++ aId.is(mId)
val cond = mPages.isNull
(selectSimple(cols, join, cond) ++ orderBy(aCreated.desc))
.query[RAttachment]
.streamWithChunkSize(chunkSize)
// val aId = Columns.id.prefix("a")
// val aCreated = Columns.created.prefix("a")
// val mId = RAttachmentMeta.Columns.id.prefix("m")
// val mPages = RAttachmentMeta.Columns.pages.prefix("m")
//
// val cols = all.map(_.prefix("a"))
// val join = table ++ fr"a LEFT OUTER JOIN" ++
// RAttachmentMeta.table ++ fr"m ON" ++ aId.is(mId)
// val cond = mPages.isNull
//
// (selectSimple(cols, join, cond) ++ orderBy(aCreated.desc))
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
val a = RAttachment.as("a")
val m = RAttachmentMeta.as("m")
Select(
select(a.all),
from(a)
.leftJoin(m, a.id === m.id),
m.pages.isNull
).build.query[RAttachment].streamWithChunkSize(chunkSize)
}
def findWithoutPreview(
coll: Option[Ident],
chunkSize: Int
): Stream[ConnectionIO, RAttachment] = {
val aId = Columns.id.prefix("a")
val aItem = Columns.itemId.prefix("a")
val aCreated = Columns.created.prefix("a")
val pId = RAttachmentPreview.Columns.id.prefix("p")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
// val aId = Columns.id.prefix("a")
// val aItem = Columns.itemId.prefix("a")
// val aCreated = Columns.created.prefix("a")
// val pId = RAttachmentPreview.Columns.id.prefix("p")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val cols = all.map(_.prefix("a"))
// val baseJoin =
// table ++ fr"a LEFT OUTER JOIN" ++
// RAttachmentPreview.table ++ fr"p ON" ++ pId.is(aId)
//
// val baseCond =
// Seq(pId.isNull)
//
// coll match {
// case Some(cid) =>
// val join = baseJoin ++ fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
// val cond = and(baseCond ++ Seq(iColl.is(cid)))
// (selectSimple(cols, join, cond) ++ orderBy(aCreated.desc))
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
// case None =>
// (selectSimple(cols, baseJoin, and(baseCond)) ++ orderBy(aCreated.desc))
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
// }
val a = RAttachment.as("a")
val p = RAttachmentPreview.as("p")
val i = RItem.as("i")
val cols = all.map(_.prefix("a"))
val baseJoin =
table ++ fr"a LEFT OUTER JOIN" ++
RAttachmentPreview.table ++ fr"p ON" ++ pId.is(aId)
val baseCond =
Seq(pId.isNull)
coll match {
case Some(cid) =>
val join = baseJoin ++ fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
val cond = and(baseCond ++ Seq(iColl.is(cid)))
(selectSimple(cols, join, cond) ++ orderBy(aCreated.desc))
.query[RAttachment]
.streamWithChunkSize(chunkSize)
case None =>
(selectSimple(cols, baseJoin, and(baseCond)) ++ orderBy(aCreated.desc))
.query[RAttachment]
.streamWithChunkSize(chunkSize)
}
val baseJoin = from(a).leftJoin(p, p.id === a.id)
Select(
select(a.all),
coll.map(_ => baseJoin.innerJoin(i, i.id === a.itemId)).getOrElse(baseJoin),
p.id.isNull &&? coll.map(cid => i.cid === cid)
).orderBy(a.created.asc).build.query[RAttachment].streamWithChunkSize(chunkSize)
}
def findNonConvertedPdf(
coll: Option[Ident],
chunkSize: Int
): Stream[ConnectionIO, RAttachment] = {
val aId = Columns.id.prefix("a")
val aItem = Columns.itemId.prefix("a")
val aFile = Columns.fileId.prefix("a")
val sId = RAttachmentSource.Columns.id.prefix("s")
val sFile = RAttachmentSource.Columns.fileId.prefix("s")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val mId = RFileMeta.Columns.id.prefix("m")
val mType = RFileMeta.Columns.mimetype.prefix("m")
// val aId = Columns.id.prefix("a")
// val aItem = Columns.itemId.prefix("a")
// val aFile = Columns.fileId.prefix("a")
// val sId = RAttachmentSource.Columns.id.prefix("s")
// val sFile = RAttachmentSource.Columns.fileId.prefix("s")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
// val mId = RFileMeta.Columns.id.prefix("m")
// val mType = RFileMeta.Columns.mimetype.prefix("m")
val pdfType = "application/pdf%"
//
// val from = table ++ fr"a INNER JOIN" ++
// RAttachmentSource.table ++ fr"s ON" ++ sId.is(aId) ++ fr"INNER JOIN" ++
// RItem.table ++ fr"i ON" ++ iId.is(aItem) ++ fr"INNER JOIN" ++
// RFileMeta.table ++ fr"m ON" ++ aFile.is(mId)
// val where = coll match {
// case Some(cid) => and(iColl.is(cid), aFile.is(sFile), mType.lowerLike(pdfType))
// case None => and(aFile.is(sFile), mType.lowerLike(pdfType))
// }
// selectSimple(all.map(_.prefix("a")), from, where)
// .query[RAttachment]
// .streamWithChunkSize(chunkSize)
val a = RAttachment.as("a")
val s = RAttachmentSource.as("s")
val i = RItem.as("i")
val m = RFileMeta.as("m")
val from = table ++ fr"a INNER JOIN" ++
RAttachmentSource.table ++ fr"s ON" ++ sId.is(aId) ++ fr"INNER JOIN" ++
RItem.table ++ fr"i ON" ++ iId.is(aItem) ++ fr"INNER JOIN" ++
RFileMeta.table ++ fr"m ON" ++ aFile.is(mId)
val where = coll match {
case Some(cid) => and(iColl.is(cid), aFile.is(sFile), mType.lowerLike(pdfType))
case None => and(aFile.is(sFile), mType.lowerLike(pdfType))
}
selectSimple(all.map(_.prefix("a")), from, where)
.query[RAttachment]
.streamWithChunkSize(chunkSize)
Select(
select(a.all),
from(a)
.innerJoin(s, s.id === a.id)
.innerJoin(i, i.id === a.itemId)
.innerJoin(m, m.id === a.fileId),
a.fileId === s.fileId &&
m.mimetype.likes(pdfType) &&?
coll.map(cid => i.cid === cid)
).build.query[RAttachment].streamWithChunkSize(chunkSize)
}
}

View File

@ -3,8 +3,9 @@ package docspell.store.records
import cats.data.NonEmptyList
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb.TableDef
import docspell.store.qb._
import bitpeace.FileMeta
import doobie._
@ -22,10 +23,25 @@ case class RAttachmentArchive(
)
object RAttachmentArchive {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "attachment_archive"
val id = Column[Ident]("id", this)
val fileId = Column[Ident]("file_id", this)
val name = Column[String]("filename", this)
val messageId = Column[String]("message_id", this)
val created = Column[Timestamp]("created", this)
val all = NonEmptyList.of[Column[_]](id, fileId, name, messageId, created)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
val table = fr"attachment_archive"
object Columns {
import docspell.store.impl._
val id = Column("id")
val fileId = Column("file_id")
val name = Column("filename")
@ -35,64 +51,83 @@ object RAttachmentArchive {
val all = List(id, fileId, name, messageId, created)
}
import Columns._
def of(ra: RAttachment, mId: Option[String]): RAttachmentArchive =
RAttachmentArchive(ra.id, ra.fileId, ra.name, mId, ra.created)
def insert(v: RAttachmentArchive): ConnectionIO[Int] =
insertRow(
table,
all,
DML.insert(
T,
T.all,
fr"${v.id},${v.fileId},${v.name},${v.messageId},${v.created}"
).update.run
)
def findById(attachId: Ident): ConnectionIO[Option[RAttachmentArchive]] =
selectSimple(all, table, id.is(attachId)).query[RAttachmentArchive].option
run(select(T.all), from(T), T.id === attachId).query[RAttachmentArchive].option
def delete(attachId: Ident): ConnectionIO[Int] =
deleteFrom(table, id.is(attachId)).update.run
DML.delete(T, T.id === attachId)
def deleteAll(fId: Ident): ConnectionIO[Int] =
deleteFrom(table, fileId.is(fId)).update.run
DML.delete(T, T.fileId === fId)
def findByIdAndCollective(
attachId: Ident,
collective: Ident
): ConnectionIO[Option[RAttachmentArchive]] = {
val bId = RAttachment.Columns.id.prefix("b")
val aId = Columns.id.prefix("a")
val bItem = RAttachment.Columns.itemId.prefix("b")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
// val bId = RAttachment.Columns.id.prefix("b")
// val aId = Columns.id.prefix("a")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from = table ++ fr"a INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
//
// val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
//
// selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentArchive].option
val b = RAttachment.as("b")
val a = RAttachmentArchive.as("a")
val i = RItem.as("i")
val from = table ++ fr"a INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentArchive].option
Select(
select(a.all),
from(a)
.innerJoin(b, b.id === a.id)
.innerJoin(i, i.id === b.itemId),
a.id === attachId && b.id === attachId && i.cid === collective
).build.query[RAttachmentArchive].option
}
def findByMessageIdAndCollective(
messageIds: NonEmptyList[String],
collective: Ident
): ConnectionIO[Vector[RAttachmentArchive]] = {
val bId = RAttachment.Columns.id.prefix("b")
val bItem = RAttachment.Columns.itemId.prefix("b")
val aMsgId = Columns.messageId.prefix("a")
val aId = Columns.id.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
val from = table ++ fr"a INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
val where = and(aMsgId.isIn(messageIds), iColl.is(collective))
selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentArchive].to[Vector]
// val bId = RAttachment.Columns.id.prefix("b")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val aMsgId = Columns.messageId.prefix("a")
// val aId = Columns.id.prefix("a")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from = table ++ fr"a INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
//
// val where = and(aMsgId.isIn(messageIds), iColl.is(collective))
//
// selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentArchive].to[Vector]
val b = RAttachment.as("b")
val a = RAttachmentArchive.as("a")
val i = RItem.as("i")
Select(
select(a.all),
from(a)
.innerJoin(b, b.id === a.id)
.innerJoin(i, i.id === b.itemId),
a.messageId.in(messageIds) && i.cid === collective
).build.query[RAttachmentArchive].to[Vector]
}
def findByItemWithMeta(
@ -100,31 +135,49 @@ object RAttachmentArchive {
): ConnectionIO[Vector[(RAttachmentArchive, FileMeta)]] = {
import bitpeace.sql._
val aId = Columns.id.prefix("a")
val afileMeta = fileId.prefix("a")
val bPos = RAttachment.Columns.position.prefix("b")
val bId = RAttachment.Columns.id.prefix("b")
val bItem = RAttachment.Columns.itemId.prefix("b")
val mId = RFileMeta.Columns.id.prefix("m")
val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
val from = table ++ fr"a INNER JOIN" ++
RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++ fr"INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId)
val where = bItem.is(id)
(selectSimple(cols, from, where) ++ orderBy(bPos.asc))
.query[(RAttachmentArchive, FileMeta)]
.to[Vector]
// val aId = Columns.id.prefix("a")
// val afileMeta = fileId.prefix("a")
// val bPos = RAttachment.Columns.position.prefix("b")
// val bId = RAttachment.Columns.id.prefix("b")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val mId = RFileMeta.as("m").id.column
//
// val cols = all.map(_.prefix("a")) ++ RFileMeta.as("m").all.map(_.column).toList
// val from = table ++ fr"a INNER JOIN" ++
// Fragment.const(RFileMeta.T.tableName) ++ fr"m ON" ++ afileMeta.is(
// mId
// ) ++ fr"INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId)
// val where = bItem.is(id)
//
// (selectSimple(cols, from, where) ++ orderBy(bPos.asc))
// .query[(RAttachmentArchive, FileMeta)]
// .to[Vector]
val a = RAttachmentArchive.as("a")
val b = RAttachment.as("b")
val m = RFileMeta.as("m")
Select(
select(a.all, m.all),
from(a)
.innerJoin(m, a.fileId === m.id)
.innerJoin(b, a.id === b.id),
b.itemId === id
).orderBy(b.position.asc).build.query[(RAttachmentArchive, FileMeta)].to[Vector]
}
/** If the given attachment id has an associated archive, this returns
* the number of all associated attachments. Returns 0 if there is
* no archive for the given attachment.
*/
def countEntries(attachId: Ident): ConnectionIO[Int] = {
val qFileId = selectSimple(Seq(fileId), table, id.is(attachId))
val q = selectCount(id, table, fileId.isSubquery(qFileId))
q.query[Int].unique
}
def countEntries(attachId: Ident): ConnectionIO[Int] =
// val qFileId = selectSimple(Seq(fileId), table, id.is(attachId))
// val q = selectCount(id, table, fileId.isSubquery(qFileId))
// q.query[Int].unique
Select(
count(T.id).s,
from(T),
T.fileId.in(Select(T.fileId.s, from(T), T.id === attachId))
).build.query[Int].unique
//TODO this looks strange, can be simplified
}

View File

@ -1,10 +1,11 @@
package docspell.store.records
import cats.data.NonEmptyList
import cats.implicits._
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._
@ -29,9 +30,25 @@ object RAttachmentMeta {
def empty(attachId: Ident) =
RAttachmentMeta(attachId, None, Nil, MetaProposalList.empty, None)
val table = fr"attachmentmeta"
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "attachmentmeta"
val id = Column[Ident]("attachid", this)
val content = Column[String]("content", this)
val nerlabels = Column[List[NerLabel]]("nerlabels", this)
val proposals = Column[MetaProposalList]("itemproposals", this)
val pages = Column[Int]("page_count", this)
val all = NonEmptyList.of[Column[_]](id, content, nerlabels, proposals, pages)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
val table = fr"attachmentmeta"
object Columns {
import docspell.store.impl._
val id = Column("attachid")
val content = Column("content")
val nerlabels = Column("nerlabels")
@ -39,23 +56,22 @@ object RAttachmentMeta {
val pages = Column("page_count")
val all = List(id, content, nerlabels, proposals, pages)
}
import Columns._
def insert(v: RAttachmentMeta): ConnectionIO[Int] =
insertRow(
table,
all,
DML.insert(
T,
T.all,
fr"${v.id},${v.content},${v.nerlabels},${v.proposals},${v.pages}"
).update.run
)
def exists(attachId: Ident): ConnectionIO[Boolean] =
selectCount(id, table, id.is(attachId)).query[Int].unique.map(_ > 0)
Select(count(T.id).s, from(T), T.id === attachId).build.query[Int].unique.map(_ > 0)
def findById(attachId: Ident): ConnectionIO[Option[RAttachmentMeta]] =
selectSimple(all, table, id.is(attachId)).query[RAttachmentMeta].option
run(select(T.all), from(T), T.id === attachId).query[RAttachmentMeta].option
def findPageCountById(attachId: Ident): ConnectionIO[Option[Int]] =
selectSimple(Seq(pages), table, id.is(attachId))
Select(T.pages.s, from(T), T.id === attachId).build
.query[Option[Int]]
.option
.map(_.flatten)
@ -67,37 +83,37 @@ object RAttachmentMeta {
} yield n1
def update(v: RAttachmentMeta): ConnectionIO[Int] =
updateRow(
table,
id.is(v.id),
commas(
content.setTo(v.content),
nerlabels.setTo(v.nerlabels),
proposals.setTo(v.proposals)
DML.update(
T,
T.id === v.id,
DML.set(
T.content.setTo(v.content),
T.nerlabels.setTo(v.nerlabels),
T.proposals.setTo(v.proposals)
)
).update.run
)
def updateLabels(mid: Ident, labels: List[NerLabel]): ConnectionIO[Int] =
updateRow(
table,
id.is(mid),
commas(
nerlabels.setTo(labels)
DML.update(
T,
T.id === mid,
DML.set(
T.nerlabels.setTo(labels)
)
).update.run
)
def updateProposals(mid: Ident, plist: MetaProposalList): ConnectionIO[Int] =
updateRow(
table,
id.is(mid),
commas(
proposals.setTo(plist)
DML.update(
T,
T.id === mid,
DML.set(
T.proposals.setTo(plist)
)
).update.run
)
def updatePageCount(mid: Ident, pageCount: Option[Int]): ConnectionIO[Int] =
updateRow(table, id.is(mid), pages.setTo(pageCount)).update.run
DML.update(T, T.id === mid, DML.set(T.pages.setTo(pageCount)))
def delete(attachId: Ident): ConnectionIO[Int] =
deleteFrom(table, id.is(attachId)).update.run
DML.delete(T, T.id === attachId)
}

View File

@ -1,8 +1,10 @@
package docspell.store.records
import cats.data.NonEmptyList
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb._
import bitpeace.FileMeta
import doobie._
@ -19,10 +21,24 @@ case class RAttachmentPreview(
)
object RAttachmentPreview {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "attachment_preview"
val id = Column[Ident]("id", this)
val fileId = Column[Ident]("file_id", this)
val name = Column[String]("filename", this)
val created = Column[Timestamp]("created", this)
val all = NonEmptyList.of[Column[_]](id, fileId, name, created)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
val table = fr"attachment_preview"
object Columns {
import docspell.store.impl._
val id = Column("id")
val fileId = Column("file_id")
val name = Column("filename")
@ -31,67 +47,98 @@ object RAttachmentPreview {
val all = List(id, fileId, name, created)
}
import Columns._
def insert(v: RAttachmentPreview): ConnectionIO[Int] =
insertRow(table, all, fr"${v.id},${v.fileId},${v.name},${v.created}").update.run
DML.insert(T, T.all, fr"${v.id},${v.fileId},${v.name},${v.created}")
def findById(attachId: Ident): ConnectionIO[Option[RAttachmentPreview]] =
selectSimple(all, table, id.is(attachId)).query[RAttachmentPreview].option
run(select(T.all), from(T), T.id === attachId).query[RAttachmentPreview].option
def delete(attachId: Ident): ConnectionIO[Int] =
deleteFrom(table, id.is(attachId)).update.run
DML.delete(T, T.id === attachId)
def findByIdAndCollective(
attachId: Ident,
collective: Ident
): ConnectionIO[Option[RAttachmentPreview]] = {
val bId = RAttachment.Columns.id.prefix("b")
val aId = Columns.id.prefix("a")
val bItem = RAttachment.Columns.itemId.prefix("b")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
// val bId = RAttachment.Columns.id.prefix("b")
// val aId = Columns.id.prefix("a")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from = table ++ fr"a INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
//
// val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
//
// selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentPreview].option
val b = RAttachment.as("b")
val a = RAttachmentPreview.as("a")
val i = RItem.as("i")
val from = table ++ fr"a INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentPreview].option
Select(
select(a.all),
from(a)
.innerJoin(b, a.id === b.id)
.innerJoin(i, i.id === b.itemId),
a.id === attachId && b.id === attachId && i.cid === collective
).build.query[RAttachmentPreview].option
}
def findByItem(itemId: Ident): ConnectionIO[Vector[RAttachmentPreview]] = {
val sId = Columns.id.prefix("s")
val aId = RAttachment.Columns.id.prefix("a")
val aItem = RAttachment.Columns.itemId.prefix("a")
val from = table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId)
selectSimple(all.map(_.prefix("s")), from, aItem.is(itemId))
.query[RAttachmentPreview]
.to[Vector]
// val sId = Columns.id.prefix("s")
// val aId = RAttachment.Columns.id.prefix("a")
// val aItem = RAttachment.Columns.itemId.prefix("a")
//
// val from = table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId)
// selectSimple(all.map(_.prefix("s")), from, aItem.is(itemId))
// .query[RAttachmentPreview]
// .to[Vector]
val s = RAttachmentPreview.as("s")
val a = RAttachment.as("a")
Select(
select(s.all),
from(s)
.innerJoin(a, s.id === a.id),
a.itemId === itemId
).build.query[RAttachmentPreview].to[Vector]
}
def findByItemAndCollective(
itemId: Ident,
coll: Ident
): ConnectionIO[Option[RAttachmentPreview]] = {
val sId = Columns.id.prefix("s")
val aId = RAttachment.Columns.id.prefix("a")
val aItem = RAttachment.Columns.itemId.prefix("a")
val aPos = RAttachment.Columns.position.prefix("a")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
// val sId = Columns.id.prefix("s")
// val aId = RAttachment.Columns.id.prefix("a")
// val aItem = RAttachment.Columns.itemId.prefix("a")
// val aPos = RAttachment.Columns.position.prefix("a")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from =
// table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
//
// selectSimple(
// all.map(_.prefix("s")) ++ List(aPos),
// from,
// and(aItem.is(itemId), iColl.is(coll))
// )
// .query[(RAttachmentPreview, Int)]
// .to[Vector]
// .map(_.sortBy(_._2).headOption.map(_._1))
val s = RAttachmentPreview.as("s")
val a = RAttachment.as("a")
val i = RItem.as("i")
val from =
table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ iId.is(aItem)
selectSimple(
all.map(_.prefix("s")) ++ List(aPos),
from,
and(aItem.is(itemId), iColl.is(coll))
)
Select(
select(s.all).append(a.position.s),
from(s)
.innerJoin(a, s.id === a.id)
.innerJoin(i, i.id === a.itemId),
a.itemId === itemId && i.cid === coll
).build
.query[(RAttachmentPreview, Int)]
.to[Vector]
.map(_.sortBy(_._2).headOption.map(_._1))
@ -102,22 +149,33 @@ object RAttachmentPreview {
): ConnectionIO[Vector[(RAttachmentPreview, FileMeta)]] = {
import bitpeace.sql._
val aId = Columns.id.prefix("a")
val afileMeta = fileId.prefix("a")
val bPos = RAttachment.Columns.position.prefix("b")
val bId = RAttachment.Columns.id.prefix("b")
val bItem = RAttachment.Columns.itemId.prefix("b")
val mId = RFileMeta.Columns.id.prefix("m")
// val aId = Columns.id.prefix("a")
// val afileMeta = fileId.prefix("a")
// val bPos = RAttachment.Columns.position.prefix("b")
// val bId = RAttachment.Columns.id.prefix("b")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val mId = RFileMeta.Columns.id.prefix("m")
//
// val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
// val from = table ++ fr"a INNER JOIN" ++
// RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++ fr"INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId)
// val where = bItem.is(id)
//
// (selectSimple(cols, from, where) ++ orderBy(bPos.asc))
// .query[(RAttachmentPreview, FileMeta)]
// .to[Vector]
val a = RAttachmentPreview.as("a")
val b = RAttachment.as("b")
val m = RFileMeta.as("m")
val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
val from = table ++ fr"a INNER JOIN" ++
RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++ fr"INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId)
val where = bItem.is(id)
(selectSimple(cols, from, where) ++ orderBy(bPos.asc))
.query[(RAttachmentPreview, FileMeta)]
.to[Vector]
Select(
select(a.all, m.all),
from(a)
.innerJoin(m, a.fileId === m.id)
.innerJoin(b, b.id === a.id),
b.itemId === id
).orderBy(b.position.asc).build.query[(RAttachmentPreview, FileMeta)].to[Vector]
}
}

View File

@ -1,8 +1,10 @@
package docspell.store.records
import cats.data.NonEmptyList
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb._
import bitpeace.FileMeta
import doobie._
@ -19,10 +21,24 @@ case class RAttachmentSource(
)
object RAttachmentSource {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "attachment_source"
val id = Column[Ident]("id", this)
val fileId = Column[Ident]("file_id", this)
val name = Column[String]("filename", this)
val created = Column[Timestamp]("created", this)
val all = NonEmptyList.of[Column[_]](id, fileId, name, created)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
val table = fr"attachment_source"
object Columns {
import docspell.store.impl._
val id = Column("id")
val fileId = Column("file_id")
val name = Column("filename")
@ -31,67 +47,90 @@ object RAttachmentSource {
val all = List(id, fileId, name, created)
}
import Columns._
def of(ra: RAttachment): RAttachmentSource =
RAttachmentSource(ra.id, ra.fileId, ra.name, ra.created)
def insert(v: RAttachmentSource): ConnectionIO[Int] =
insertRow(table, all, fr"${v.id},${v.fileId},${v.name},${v.created}").update.run
DML.insert(T, T.all, fr"${v.id},${v.fileId},${v.name},${v.created}")
def findById(attachId: Ident): ConnectionIO[Option[RAttachmentSource]] =
selectSimple(all, table, id.is(attachId)).query[RAttachmentSource].option
run(select(T.all), from(T), T.id === attachId).query[RAttachmentSource].option
def isSameFile(attachId: Ident, file: Ident): ConnectionIO[Boolean] =
selectCount(id, table, and(id.is(attachId), fileId.is(file)))
Select(count(T.id).s, from(T), T.id === attachId && T.fileId === file).build
.query[Int]
.unique
.map(_ > 0)
def isConverted(attachId: Ident): ConnectionIO[Boolean] = {
val sId = Columns.id.prefix("s")
val sFile = Columns.fileId.prefix("s")
val aId = RAttachment.Columns.id.prefix("a")
val aFile = RAttachment.Columns.fileId.prefix("a")
val s = RAttachmentSource.as("s")
val a = RAttachment.as("a")
Select(
count(a.id).s,
from(s).innerJoin(a, a.id === s.id),
a.id === attachId && a.fileId <> s.fileId
).build.query[Int].unique.map(_ > 0)
val from = table ++ fr"s INNER JOIN" ++
RAttachment.table ++ fr"a ON" ++ aId.is(sId)
selectCount(aId, from, and(aId.is(attachId), aFile.isNot(sFile)))
.query[Int]
.unique
.map(_ > 0)
// val sId = Columns.id.prefix("s")
// val sFile = Columns.fileId.prefix("s")
// val aId = RAttachment.Columns.id.prefix("a")
// val aFile = RAttachment.Columns.fileId.prefix("a")
//
// val from = table ++ fr"s INNER JOIN" ++
// RAttachment.table ++ fr"a ON" ++ aId.is(sId)
//
// selectCount(aId, from, and(aId.is(attachId), aFile.isNot(sFile)))
// .query[Int]
// .unique
// .map(_ > 0)
}
def delete(attachId: Ident): ConnectionIO[Int] =
deleteFrom(table, id.is(attachId)).update.run
DML.delete(T, T.id === attachId)
def findByIdAndCollective(
attachId: Ident,
collective: Ident
): ConnectionIO[Option[RAttachmentSource]] = {
val bId = RAttachment.Columns.id.prefix("b")
val aId = Columns.id.prefix("a")
val bItem = RAttachment.Columns.itemId.prefix("b")
val iId = RItem.Columns.id.prefix("i")
val iColl = RItem.Columns.cid.prefix("i")
// val bId = RAttachment.Columns.id.prefix("b")
// val aId = Columns.id.prefix("a")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val iId = RItem.Columns.id.prefix("i")
// val iColl = RItem.Columns.cid.prefix("i")
//
// val from = table ++ fr"a INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
// fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
//
// val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
//
// selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentSource].option
val b = RAttachment.as("b")
val a = RAttachmentSource.as("a")
val i = RItem.as("i")
val from = table ++ fr"a INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId) ++
fr"INNER JOIN" ++ RItem.table ++ fr"i ON" ++ bItem.is(iId)
val where = and(aId.is(attachId), bId.is(attachId), iColl.is(collective))
selectSimple(all.map(_.prefix("a")), from, where).query[RAttachmentSource].option
Select(
select(a.all),
from(a)
.innerJoin(b, a.id === b.id)
.innerJoin(i, i.id === b.itemId),
a.id === attachId && b.id === attachId && i.cid === collective
).build.query[RAttachmentSource].option
}
def findByItem(itemId: Ident): ConnectionIO[Vector[RAttachmentSource]] = {
val sId = Columns.id.prefix("s")
val aId = RAttachment.Columns.id.prefix("a")
val aItem = RAttachment.Columns.itemId.prefix("a")
// val sId = Columns.id.prefix("s")
// val aId = RAttachment.Columns.id.prefix("a")
// val aItem = RAttachment.Columns.itemId.prefix("a")
//
// val from = table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId)
// selectSimple(all.map(_.prefix("s")), from, aItem.is(itemId))
// .query[RAttachmentSource]
// .to[Vector]
val from = table ++ fr"s INNER JOIN" ++ RAttachment.table ++ fr"a ON" ++ sId.is(aId)
selectSimple(all.map(_.prefix("s")), from, aItem.is(itemId))
val s = RAttachmentSource.as("s")
val a = RAttachment.as("a")
Select(select(s.all), from(s).innerJoin(a, a.id === s.id), a.itemId === itemId).build
.query[RAttachmentSource]
.to[Vector]
}
@ -101,22 +140,33 @@ object RAttachmentSource {
): ConnectionIO[Vector[(RAttachmentSource, FileMeta)]] = {
import bitpeace.sql._
val aId = Columns.id.prefix("a")
val afileMeta = fileId.prefix("a")
val bPos = RAttachment.Columns.position.prefix("b")
val bId = RAttachment.Columns.id.prefix("b")
val bItem = RAttachment.Columns.itemId.prefix("b")
val mId = RFileMeta.Columns.id.prefix("m")
// val aId = Columns.id.prefix("a")
// val afileMeta = fileId.prefix("a")
// val bPos = RAttachment.Columns.position.prefix("b")
// val bId = RAttachment.Columns.id.prefix("b")
// val bItem = RAttachment.Columns.itemId.prefix("b")
// val mId = RFileMeta.Columns.id.prefix("m")
//
// val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
// val from = table ++ fr"a INNER JOIN" ++
// RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++ fr"INNER JOIN" ++
// RAttachment.table ++ fr"b ON" ++ aId.is(bId)
// val where = bItem.is(id)
//
// (selectSimple(cols, from, where) ++ orderBy(bPos.asc))
// .query[(RAttachmentSource, FileMeta)]
// .to[Vector]
val a = RAttachmentSource.as("a")
val b = RAttachment.as("b")
val m = RFileMeta.as("m")
val cols = all.map(_.prefix("a")) ++ RFileMeta.Columns.all.map(_.prefix("m"))
val from = table ++ fr"a INNER JOIN" ++
RFileMeta.table ++ fr"m ON" ++ afileMeta.is(mId) ++ fr"INNER JOIN" ++
RAttachment.table ++ fr"b ON" ++ aId.is(bId)
val where = bItem.is(id)
(selectSimple(cols, from, where) ++ orderBy(bPos.asc))
.query[(RAttachmentSource, FileMeta)]
.to[Vector]
Select(
select(a.all, m.all),
from(a)
.innerJoin(m, a.fileId === m.id)
.innerJoin(b, b.id === a.id),
b.itemId === id
).orderBy(b.position.asc).build.query[(RAttachmentSource, FileMeta)].to[Vector]
}
}

View File

@ -1,10 +1,11 @@
package docspell.store.records
import cats.data.NonEmptyList
import cats.implicits._
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb._
import com.github.eikek.calev._
import doobie._
@ -21,71 +22,69 @@ case class RClassifierSetting(
) {}
object RClassifierSetting {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "classifier_setting"
val table = fr"classifier_setting"
object Columns {
val cid = Column("cid")
val enabled = Column("enabled")
val schedule = Column("schedule")
val category = Column("category")
val itemCount = Column("item_count")
val fileId = Column("file_id")
val created = Column("created")
val all = List(cid, enabled, schedule, category, itemCount, fileId, created)
}
import Columns._
def insert(v: RClassifierSetting): ConnectionIO[Int] = {
val sql =
insertRow(
table,
all,
fr"${v.cid},${v.enabled},${v.schedule},${v.category},${v.itemCount},${v.fileId},${v.created}"
)
sql.update.run
val cid = Column[Ident]("cid", this)
val enabled = Column[Boolean]("enabled", this)
val schedule = Column[CalEvent]("schedule", this)
val category = Column[String]("category", this)
val itemCount = Column[Int]("item_count", this)
val fileId = Column[Ident]("file_id", this)
val created = Column[Timestamp]("created", this)
val all = NonEmptyList
.of[Column[_]](cid, enabled, schedule, category, itemCount, fileId, created)
}
def updateAll(v: RClassifierSetting): ConnectionIO[Int] = {
val sql = updateRow(
table,
cid.is(v.cid),
commas(
enabled.setTo(v.enabled),
schedule.setTo(v.schedule),
category.setTo(v.category),
itemCount.setTo(v.itemCount),
fileId.setTo(v.fileId)
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
def insert(v: RClassifierSetting): ConnectionIO[Int] =
DML.insert(
T,
T.all,
fr"${v.cid},${v.enabled},${v.schedule},${v.category},${v.itemCount},${v.fileId},${v.created}"
)
def updateAll(v: RClassifierSetting): ConnectionIO[Int] =
DML.update(
T,
T.cid === v.cid,
DML.set(
T.enabled.setTo(v.enabled),
T.schedule.setTo(v.schedule),
T.category.setTo(v.category),
T.itemCount.setTo(v.itemCount),
T.fileId.setTo(v.fileId)
)
)
sql.update.run
}
def updateFile(coll: Ident, fid: Ident): ConnectionIO[Int] =
updateRow(table, cid.is(coll), fileId.setTo(fid)).update.run
DML.update(T, T.cid === coll, DML.set(T.fileId.setTo(fid)))
def updateSettings(v: RClassifierSetting): ConnectionIO[Int] =
for {
n1 <- updateRow(
table,
cid.is(v.cid),
commas(
enabled.setTo(v.enabled),
schedule.setTo(v.schedule),
itemCount.setTo(v.itemCount),
category.setTo(v.category)
n1 <- DML.update(
T,
T.cid === v.cid,
DML.set(
T.enabled.setTo(v.enabled),
T.schedule.setTo(v.schedule),
T.itemCount.setTo(v.itemCount),
T.category.setTo(v.category)
)
).update.run
)
n2 <- if (n1 <= 0) insert(v) else 0.pure[ConnectionIO]
} yield n1 + n2
def findById(id: Ident): ConnectionIO[Option[RClassifierSetting]] = {
val sql = selectSimple(all, table, cid.is(id))
val sql = run(select(T.all), from(T), T.cid === id)
sql.query[RClassifierSetting].option
}
def delete(coll: Ident): ConnectionIO[Int] =
deleteFrom(table, cid.is(coll)).update.run
DML.delete(T, T.cid === coll)
case class Classifier(
enabled: Boolean,

View File

@ -1,10 +1,11 @@
package docspell.store.records
import cats.data.NonEmptyList
import fs2.Stream
import docspell.common._
import docspell.store.impl.Column
import docspell.store.impl.Implicits._
import docspell.store.qb.DSL._
import docspell.store.qb._
import doobie._
import doobie.implicits._
@ -18,58 +19,54 @@ case class RCollective(
)
object RCollective {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "collective"
val table = fr"collective"
val id = Column[Ident]("cid", this)
val state = Column[CollectiveState]("state", this)
val language = Column[Language]("doclang", this)
val integration = Column[Boolean]("integration_enabled", this)
val created = Column[Timestamp]("created", this)
object Columns {
val id = Column("cid")
val state = Column("state")
val language = Column("doclang")
val integration = Column("integration_enabled")
val created = Column("created")
val all = List(id, state, language, integration, created)
val all = NonEmptyList.of[Column[_]](id, state, language, integration, created)
}
import Columns._
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
def insert(value: RCollective): ConnectionIO[Int] = {
val sql = insertRow(
table,
Columns.all,
def insert(value: RCollective): ConnectionIO[Int] =
DML.insert(
T,
T.all,
fr"${value.id},${value.state},${value.language},${value.integrationEnabled},${value.created}"
)
sql.update.run
}
def update(value: RCollective): ConnectionIO[Int] = {
val sql = updateRow(
table,
id.is(value.id),
commas(
state.setTo(value.state)
def update(value: RCollective): ConnectionIO[Int] =
DML.update(
T,
T.id === value.id,
DML.set(
T.state.setTo(value.state)
)
)
sql.update.run
}
def findLanguage(cid: Ident): ConnectionIO[Option[Language]] =
selectSimple(List(language), table, id.is(cid)).query[Option[Language]].unique
Select(T.language.s, from(T), T.id === cid).build.query[Option[Language]].unique
def updateLanguage(cid: Ident, lang: Language): ConnectionIO[Int] =
updateRow(table, id.is(cid), language.setTo(lang)).update.run
DML.update(T, T.id === cid, DML.set(T.language.setTo(lang)))
def updateSettings(cid: Ident, settings: Settings): ConnectionIO[Int] =
for {
n1 <- updateRow(
table,
id.is(cid),
commas(
language.setTo(settings.language),
integration.setTo(settings.integrationEnabled)
n1 <- DML.update(
T,
T.id === cid,
DML.set(
T.language.setTo(settings.language),
T.integration.setTo(settings.integrationEnabled)
)
).update.run
)
cls <-
Timestamp
.current[ConnectionIO]
@ -83,66 +80,64 @@ object RCollective {
} yield n1 + n2
def getSettings(coll: Ident): ConnectionIO[Option[Settings]] = {
val cId = id.prefix("c")
val CS = RClassifierSetting.Columns
val csCid = CS.cid.prefix("cs")
val c = RCollective.as("c")
val cs = RClassifierSetting.as("cs")
val cols = Seq(
language.prefix("c"),
integration.prefix("c"),
CS.enabled.prefix("cs"),
CS.schedule.prefix("cs"),
CS.itemCount.prefix("cs"),
CS.category.prefix("cs")
)
val from = table ++ fr"c LEFT JOIN" ++
RClassifierSetting.table ++ fr"cs ON" ++ csCid.is(cId)
selectSimple(cols, from, cId.is(coll))
.query[Settings]
.option
Select(
select(
c.language.s,
c.integration.s,
cs.enabled.s,
cs.schedule.s,
cs.itemCount.s,
cs.category.s
),
from(c).leftJoin(cs, cs.cid === c.id),
c.id === coll
).build.query[Settings].option
}
def findById(cid: Ident): ConnectionIO[Option[RCollective]] = {
val sql = selectSimple(all, table, id.is(cid))
val sql = run(select(T.all), from(T), T.id === cid)
sql.query[RCollective].option
}
def findByItem(itemId: Ident): ConnectionIO[Option[RCollective]] = {
val iColl = RItem.Columns.cid.prefix("i")
val iId = RItem.Columns.id.prefix("i")
val cId = id.prefix("c")
val from = RItem.table ++ fr"i INNER JOIN" ++ table ++ fr"c ON" ++ iColl.is(cId)
selectSimple(all.map(_.prefix("c")), from, iId.is(itemId)).query[RCollective].option
val i = RItem.as("i")
val c = RCollective.as("c")
Select(
select(c.all),
from(i).innerJoin(c, i.cid === c.id),
i.id === itemId
).build.query[RCollective].option
}
def existsById(cid: Ident): ConnectionIO[Boolean] = {
val sql = selectCount(id, table, id.is(cid))
val sql = Select(count(T.id).s, from(T), T.id === cid).build
sql.query[Int].unique.map(_ > 0)
}
def findAll(order: Columns.type => Column): ConnectionIO[Vector[RCollective]] = {
val sql = selectSimple(all, table, Fragment.empty) ++ orderBy(order(Columns).f)
sql.query[RCollective].to[Vector]
def findAll(order: Table => Column[_]): ConnectionIO[Vector[RCollective]] = {
val sql = Select(select(T.all), from(T)).orderBy(order(T))
sql.build.query[RCollective].to[Vector]
}
def streamAll(order: Columns.type => Column): Stream[ConnectionIO, RCollective] = {
val sql = selectSimple(all, table, Fragment.empty) ++ orderBy(order(Columns).f)
sql.query[RCollective].stream
def streamAll(order: Table => Column[_]): Stream[ConnectionIO, RCollective] = {
val sql = Select(select(T.all), from(T)).orderBy(order(T))
sql.build.query[RCollective].stream
}
def findByAttachment(attachId: Ident): ConnectionIO[Option[RCollective]] = {
val iColl = RItem.Columns.cid.prefix("i")
val iId = RItem.Columns.id.prefix("i")
val aItem = RAttachment.Columns.itemId.prefix("a")
val aId = RAttachment.Columns.id.prefix("a")
val cId = Columns.id.prefix("c")
val from = table ++ fr"c INNER JOIN" ++
RItem.table ++ fr"i ON" ++ cId.is(iColl) ++ fr"INNER JOIN" ++
RAttachment.table ++ fr"a ON" ++ aItem.is(iId)
selectSimple(all.map(_.prefix("c")), from, aId.is(attachId)).query[RCollective].option
val i = RItem.as("i")
val a = RAttachment.as("a")
val c = RCollective.as("c")
Select(
select(c.all),
from(c)
.innerJoin(i, c.id === i.cid)
.innerJoin(a, a.itemId === i.id),
a.id === attachId
).build.query[RCollective].option
}
case class Settings(

View File

@ -1,11 +1,13 @@
package docspell.store.records
import java.time.Instant
import cats.data.NonEmptyList
import cats.implicits._
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.DSL._
import docspell.store.qb._
import docspell.store.syntax.MimeTypes._
import bitpeace.FileMeta
@ -14,26 +16,30 @@ import doobie._
import doobie.implicits._
object RFileMeta {
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "filemeta"
val table = fr"filemeta"
val id = Column[Ident]("id", this)
val timestamp = Column[Instant]("timestamp", this)
val mimetype = Column[Mimetype]("mimetype", this)
val length = Column[Long]("length", this)
val checksum = Column[String]("checksum", this)
val chunks = Column[Int]("chunks", this)
val chunksize = Column[Int]("chunksize", this)
object Columns {
val id = Column("id")
val timestamp = Column("timestamp")
val mimetype = Column("mimetype")
val length = Column("length")
val checksum = Column("checksum")
val chunks = Column("chunks")
val chunksize = Column("chunksize")
val all = List(id, timestamp, mimetype, length, checksum, chunks, chunksize)
val all = NonEmptyList
.of[Column[_]](id, timestamp, mimetype, length, checksum, chunks, chunksize)
}
val T = Table(None)
def as(alias: String): Table =
Table(Some(alias))
def findById(fid: Ident): ConnectionIO[Option[FileMeta]] = {
import bitpeace.sql._
selectSimple(Columns.all, table, Columns.id.is(fid)).query[FileMeta].option
run(select(T.all), from(T), T.id === fid).query[FileMeta].option
}
def findByIds(ids: List[Ident]): ConnectionIO[Vector[FileMeta]] = {
@ -41,7 +47,7 @@ object RFileMeta {
NonEmptyList.fromList(ids) match {
case Some(nel) =>
selectSimple(Columns.all, table, Columns.id.isIn(nel)).query[FileMeta].to[Vector]
run(select(T.all), from(T), T.id.in(nel)).query[FileMeta].to[Vector]
case None =>
Vector.empty[FileMeta].pure[ConnectionIO]
}
@ -50,7 +56,7 @@ object RFileMeta {
def findMime(fid: Ident): ConnectionIO[Option[MimeType]] = {
import bitpeace.sql._
selectSimple(Seq(Columns.mimetype), table, Columns.id.is(fid))
run(select(T.mimetype), from(T), T.id === fid)
.query[Mimetype]
.option
.map(_.map(_.toLocal))

View File

@ -5,9 +5,8 @@ import cats.effect.Sync
import cats.implicits._
import docspell.common._
import docspell.store.impl.Implicits._
import docspell.store.impl._
import docspell.store.qb.{Select, TableDef}
import docspell.store.qb.DSL._
import docspell.store.qb._
import doobie._
import doobie.implicits._
@ -110,8 +109,9 @@ object RItem {
Table(Some(alias))
val table = fr"item"
object Columns {
import docspell.store.impl._
val id = Column("itemid")
val cid = Column("cid")
val name = Column("name")
@ -149,19 +149,21 @@ object RItem {
folder
)
}
import Columns._
private val currentTime =
Timestamp.current[ConnectionIO]
def insert(v: RItem): ConnectionIO[Int] =
insertRow(
table,
all,
DML.insert(
T,
T.all,
fr"${v.id},${v.cid},${v.name},${v.itemDate},${v.source},${v.direction},${v.state}," ++
fr"${v.corrOrg},${v.corrPerson},${v.concPerson},${v.concEquipment},${v.inReplyTo},${v.dueDate}," ++
fr"${v.created},${v.updated},${v.notes},${v.folderId}"
).update.run
)
def getCollective(itemId: Ident): ConnectionIO[Option[Ident]] =
selectSimple(List(cid), table, id.is(itemId)).query[Ident].option
Select(T.cid.s, from(T), T.id === itemId).build.query[Ident].option
def updateState(
itemId: Ident,
@ -170,11 +172,11 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.is(itemId), state.isIn(existing)),
commas(state.setTo(itemState), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id === itemId && T.state.in(existing),
DML.set(T.state.setTo(itemState), T.updated.setTo(t))
)
} yield n
def updateStateForCollective(
@ -184,11 +186,11 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(state.setTo(itemState), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.state.setTo(itemState), T.updated.setTo(t))
)
} yield n
def updateDirection(
@ -198,11 +200,11 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(incoming.setTo(dir), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.incoming.setTo(dir), T.updated.setTo(t))
)
} yield n
def updateCorrOrg(
@ -212,21 +214,21 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(corrOrg.setTo(org), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.corrOrg.setTo(org), T.updated.setTo(t))
)
} yield n
def removeCorrOrg(coll: Ident, currentOrg: Ident): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), corrOrg.is(Some(currentOrg))),
commas(corrOrg.setTo(None: Option[Ident]), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.cid === coll && T.corrOrg === currentOrg,
DML.set(T.corrOrg.setTo(None: Option[Ident]), T.updated.setTo(t))
)
} yield n
def updateCorrPerson(
@ -236,21 +238,21 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(corrPerson.setTo(person), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.corrPerson.setTo(person), T.updated.setTo(t))
)
} yield n
def removeCorrPerson(coll: Ident, currentPerson: Ident): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), corrPerson.is(Some(currentPerson))),
commas(corrPerson.setTo(None: Option[Ident]), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.cid === coll && T.corrPerson === currentPerson,
DML.set(T.corrPerson.setTo(None: Option[Ident]), T.updated.setTo(t))
)
} yield n
def updateConcPerson(
@ -260,21 +262,21 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(concPerson.setTo(person), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.concPerson.setTo(person), T.updated.setTo(t))
)
} yield n
def removeConcPerson(coll: Ident, currentPerson: Ident): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), concPerson.is(Some(currentPerson))),
commas(concPerson.setTo(None: Option[Ident]), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.cid === coll && T.concPerson === currentPerson,
DML.set(T.concPerson.setTo(None: Option[Ident]), T.updated.setTo(t))
)
} yield n
def updateConcEquip(
@ -284,21 +286,21 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(concEquipment.setTo(equip), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.concEquipment.setTo(equip), T.updated.setTo(t))
)
} yield n
def removeConcEquip(coll: Ident, currentEquip: Ident): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), concEquipment.is(Some(currentEquip))),
commas(concEquipment.setTo(None: Option[Ident]), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.cid === coll && T.concEquipment === currentEquip,
DML.set(T.concEquipment.setTo(None: Option[Ident]), T.updated.setTo(t))
)
} yield n
def updateFolder(
@ -308,31 +310,31 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(cid.is(coll), id.is(itemId)),
commas(folder.setTo(folderId), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.cid === coll && T.id === itemId,
DML.set(T.folder.setTo(folderId), T.updated.setTo(t))
)
} yield n
def updateNotes(itemId: Ident, coll: Ident, text: Option[String]): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.is(itemId), cid.is(coll)),
commas(notes.setTo(text), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id === itemId && T.cid === coll,
DML.set(T.notes.setTo(text), T.updated.setTo(t))
)
} yield n
def updateName(itemId: Ident, coll: Ident, itemName: String): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.is(itemId), cid.is(coll)),
commas(name.setTo(itemName), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id === itemId && T.cid === coll,
DML.set(T.name.setTo(itemName), T.updated.setTo(t))
)
} yield n
def updateDate(
@ -342,11 +344,11 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(itemDate.setTo(date), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.itemDate.setTo(date), T.updated.setTo(t))
)
} yield n
def updateDueDate(
@ -356,50 +358,50 @@ object RItem {
): ConnectionIO[Int] =
for {
t <- currentTime
n <- updateRow(
table,
and(id.isIn(itemIds), cid.is(coll)),
commas(dueDate.setTo(date), updated.setTo(t))
).update.run
n <- DML.update(
T,
T.id.in(itemIds) && T.cid === coll,
DML.set(T.dueDate.setTo(date), T.updated.setTo(t))
)
} yield n
def deleteByIdAndCollective(itemId: Ident, coll: Ident): ConnectionIO[Int] =
deleteFrom(table, and(id.is(itemId), cid.is(coll))).update.run
DML.delete(T, T.id === itemId && T.cid === coll)
def existsById(itemId: Ident): ConnectionIO[Boolean] =
selectCount(id, table, id.is(itemId)).query[Int].unique.map(_ > 0)
Select(count(T.id).s, from(T), T.id === itemId).build.query[Int].unique.map(_ > 0)
def existsByIdAndCollective(itemId: Ident, coll: Ident): ConnectionIO[Boolean] =
selectCount(id, table, and(id.is(itemId), cid.is(coll))).query[Int].unique.map(_ > 0)
Select(count(T.id).s, from(T), T.id === itemId && T.cid === coll).build
.query[Int]
.unique
.map(_ > 0)
def existsByIdsAndCollective(
itemIds: NonEmptyList[Ident],
coll: Ident
): ConnectionIO[Boolean] =
selectCount(id, table, and(id.isIn(itemIds), cid.is(coll)))
Select(count(T.id).s, from(T), T.id.in(itemIds) && T.cid === coll).build
.query[Int]
.unique
.map(_ == itemIds.size)
def findByIdAndCollective(itemId: Ident, coll: Ident): ConnectionIO[Option[RItem]] =
selectSimple(all, table, and(id.is(itemId), cid.is(coll))).query[RItem].option
run(select(T.all), from(T), T.id === itemId && T.cid === coll).query[RItem].option
def findById(itemId: Ident): ConnectionIO[Option[RItem]] =
selectSimple(all, table, id.is(itemId)).query[RItem].option
run(select(T.all), from(T), T.id === itemId).query[RItem].option
def checkByIdAndCollective(itemId: Ident, coll: Ident): ConnectionIO[Option[Ident]] =
selectSimple(Seq(id), table, and(id.is(itemId), cid.is(coll))).query[Ident].option
Select(T.id.s, from(T), T.id === itemId && T.cid === coll).build.query[Ident].option
def removeFolder(folderId: Ident): ConnectionIO[Int] = {
val empty: Option[Ident] = None
updateRow(table, folder.is(folderId), folder.setTo(empty)).update.run
DML.update(T, T.folder === folderId, DML.set(T.folder.setTo(empty)))
}
def filterItemsFragment(items: NonEmptyList[Ident], coll: Ident): Select = {
import docspell.store.qb.DSL._
def filterItemsFragment(items: NonEmptyList[Ident], coll: Ident): Select =
Select(select(T.id), from(T), T.cid === coll && T.id.in(items))
}
def filterItems(items: NonEmptyList[Ident], coll: Ident): ConnectionIO[Vector[Ident]] =
filterItemsFragment(items, coll).build.query[Ident].to[Vector]