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

@ -50,6 +50,7 @@ trait BackendApp[F[_]] {
def notification: ONotification[F]
def bookmarks: OQueryBookmarks[F]
def fileRepository: OFileRepository[F]
def itemLink: OItemLink[F]
}
object BackendApp {
@ -106,6 +107,7 @@ object BackendApp {
notifyImpl <- ONotification(store, notificationMod)
bookmarksImpl <- OQueryBookmarks(store)
fileRepoImpl <- OFileRepository(store, schedulerModule.jobs, joexImpl)
itemLinkImpl <- Resource.pure(OItemLink(store, itemSearchImpl))
} yield new BackendApp[F] {
val pubSub = pubSubT
val login = loginImpl
@ -134,5 +136,6 @@ object BackendApp {
val notification = notifyImpl
val bookmarks = bookmarksImpl
val fileRepository = fileRepoImpl
val itemLink = itemLinkImpl
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright 2020 Eike K. & Contributors
*
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
package docspell.backend.ops
import cats.data.NonEmptyList
import cats.effect._
import cats.implicits._
import docspell.backend.ops.OItemLink.LinkResult
import docspell.common.{AccountId, Ident}
import docspell.query.ItemQuery
import docspell.query.ItemQueryDsl._
import docspell.store.qb.Batch
import docspell.store.queries.Query
import docspell.store.records.RItemLink
import docspell.store.{AddResult, Store}
trait OItemLink[F[_]] {
def addAll(cid: Ident, target: Ident, related: NonEmptyList[Ident]): F[LinkResult]
def removeAll(cid: Ident, target: Ident, related: NonEmptyList[Ident]): F[Unit]
def getRelated(
account: AccountId,
item: Ident,
batch: Batch
): F[Vector[OItemSearch.ListItemWithTags]]
}
object OItemLink {
sealed trait LinkResult
object LinkResult {
/** When the target item is in the related list. */
case object LinkTargetItemError extends LinkResult
case object Success extends LinkResult
def linkTargetItemError: LinkResult = LinkTargetItemError
}
def apply[F[_]: Sync](store: Store[F], search: OItemSearch[F]): OItemLink[F] =
new OItemLink[F] {
def getRelated(
accountId: AccountId,
item: Ident,
batch: Batch
): F[Vector[OItemSearch.ListItemWithTags]] =
store
.transact(RItemLink.findLinked(accountId.collective, item))
.map(ids => NonEmptyList.fromList(ids.toList))
.flatMap {
case Some(nel) =>
val expr = Q.itemIdsIn(nel.map(_.id))
val query = Query(
Query
.Fix(accountId, Some(ItemQuery.Expr.ValidItemStates), None),
Query.QueryExpr(expr)
)
search.findItemsWithTags(0)(query, batch)
case None =>
Vector.empty[OItemSearch.ListItemWithTags].pure[F]
}
def addAll(cid: Ident, target: Ident, related: NonEmptyList[Ident]): F[LinkResult] =
if (related.contains_(target)) LinkResult.linkTargetItemError.pure[F]
else related.traverse(addSingle(cid, target, _)).as(LinkResult.Success)
def removeAll(cid: Ident, target: Ident, related: NonEmptyList[Ident]): F[Unit] =
store.transact(RItemLink.deleteAll(cid, target, related)).void
def addSingle(cid: Ident, target: Ident, related: Ident): F[Unit] = {
val exists = RItemLink.exists(cid, target, related)
val insert = RItemLink.insertNew(cid, target, related)
store.add(insert, exists).flatMap {
case AddResult.Success => ().pure[F]
case AddResult.EntityExists(_) => ().pure[F]
case AddResult.Failure(ex) =>
Sync[F].raiseError(ex)
}
}
}
}