Add routes to link items

This commit is contained in:
eikek
2022-03-14 16:54:39 +01:00
parent 1874ac070f
commit 232baf5858
12 changed files with 449 additions and 3 deletions

View File

@ -0,0 +1,11 @@
create table "item_link" (
"id" varchar(254) not null primary key,
"cid" varchar(254) not null,
"item1" varchar(254) not null,
"item2" varchar(254) not null,
"created" timestamp not null,
unique ("cid", "item1", "item2"),
foreign key ("cid") references "collective"("cid") on delete cascade,
foreign key ("item1") references "item"("itemid") on delete cascade,
foreign key ("item2") references "item"("itemid") on delete cascade
);

View File

@ -0,0 +1,11 @@
create table `item_link` (
`id` varchar(254) not null primary key,
`cid` varchar(254) not null,
`item1` varchar(254) not null,
`item2` varchar(254) not null,
`created` timestamp not null,
unique (`cid`, `item1`, `item2`),
foreign key (`cid`) references `collective`(`cid`) on delete cascade,
foreign key (`item1`) references `item`(`itemid`) on delete cascade,
foreign key (`item2`) references `item`(`itemid`) on delete cascade
);

View File

@ -0,0 +1,11 @@
create table "item_link" (
"id" varchar(254) not null primary key,
"cid" varchar(254) not null,
"item1" varchar(254) not null,
"item2" varchar(254) not null,
"created" timestamp not null,
unique ("cid", "item1", "item2"),
foreign key ("cid") references "collective"("cid") on delete cascade,
foreign key ("item1") references "item"("itemid") on delete cascade,
foreign key ("item2") references "item"("itemid") on delete cascade
);

View File

@ -27,6 +27,13 @@ object DML extends DoobieMeta {
def insert(table: TableDef, cols: Nel[Column[_]], values: Fragment): ConnectionIO[Int] =
insertFragment(table, cols, List(values)).update.run
def insertSilent(
table: TableDef,
cols: Nel[Column[_]],
values: Fragment
): ConnectionIO[Int] =
insertFragment(table, cols, List(values)).update(LogHandler.nop).run
def insertMany(
table: TableDef,
cols: Nel[Column[_]],

View File

@ -0,0 +1,120 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package docspell.store.records
import cats.Order
import cats.data.NonEmptyList
import cats.effect.Sync
import cats.implicits._
import docspell.common._
import docspell.store.qb.DSL._
import docspell.store.qb._
import doobie._
import doobie.implicits._
final case class RItemLink(
id: Ident,
cid: Ident,
item1: Ident,
item2: Ident,
created: Timestamp
)
object RItemLink {
def create[F[_]: Sync](cid: Ident, item1: Ident, item2: Ident): F[RItemLink] =
for {
id <- Ident.randomId[F]
now <- Timestamp.current[F]
} yield RItemLink(id, cid, item1, item2, now)
final case class Table(alias: Option[String]) extends TableDef {
val tableName = "item_link"
val id: Column[Ident] = Column("id", this)
val cid: Column[Ident] = Column("cid", this)
val item1: Column[Ident] = Column("item1", this)
val item2: Column[Ident] = Column("item2", this)
val created: Column[Timestamp] = Column("created", this)
val all: NonEmptyList[Column[_]] =
NonEmptyList.of(id, cid, item1, item2, created)
}
def as(alias: String): Table =
Table(Some(alias))
val T: Table = Table(None)
private def orderIds(item1: Ident, item2: Ident): (Ident, Ident) = {
val i1 = Order[Ident].min(item1, item2)
val i2 = Order[Ident].max(item1, item2)
(i1, i2)
}
def insert(r: RItemLink): ConnectionIO[Int] = {
val (i1, i2) = orderIds(r.item1, r.item2)
DML.insertSilent(T, T.all, sql"${r.id},${r.cid},$i1,$i2,${r.created}")
}
def insertNew(cid: Ident, item1: Ident, item2: Ident): ConnectionIO[Int] =
create[ConnectionIO](cid, item1, item2).flatMap(insert)
def update(r: RItemLink): ConnectionIO[Int] = {
val (i1, i2) = orderIds(r.item1, r.item2)
DML.update(
T,
T.id === r.id && T.cid === r.cid,
DML.set(
T.item1.setTo(i1),
T.item2.setTo(i2)
)
)
}
def exists(cid: Ident, item1: Ident, item2: Ident): ConnectionIO[Boolean] = {
val (i1, i2) = orderIds(item1, item2)
Select(
select(count(T.id)),
from(T),
T.cid === cid && T.item1 === i1 && T.item2 === i2
).build.query[Int].unique.map(_ > 0)
}
def findLinked(cid: Ident, item: Ident): ConnectionIO[Vector[Ident]] =
union(
Select(
select(T.item1),
from(T),
T.cid === cid && T.item2 === item
),
Select(
select(T.item2),
from(T),
T.cid === cid && T.item1 === item
)
).build.query[Ident].to[Vector]
def deleteAll(
cid: Ident,
item: Ident,
related: NonEmptyList[Ident]
): ConnectionIO[Int] =
DML.delete(
T,
T.cid === cid && (
(T.item1 === item && T.item2.in(related)) ||
(T.item2 === item && T.item1.in(related))
)
)
def delete(cid: Ident, item1: Ident, item2: Ident): ConnectionIO[Int] = {
val (i1, i2) = orderIds(item1, item2)
DML.delete(T, T.cid === cid && T.item1 === i1 && T.item2 === i2)
}
}