Change custom field values for a single item

This commit is contained in:
Eike Kettner
2020-11-16 22:06:48 +01:00
parent 62313ab03a
commit 93295d63a5
9 changed files with 274 additions and 17 deletions

View File

@ -1,10 +1,15 @@
package docspell.backend.ops
import cats.data.EitherT
import cats.data.OptionT
import cats.effect._
import cats.implicits._
import docspell.backend.ops.OCustomFields.CustomFieldData
import docspell.backend.ops.OCustomFields.NewCustomField
import docspell.backend.ops.OCustomFields.RemoveValue
import docspell.backend.ops.OCustomFields.SetValue
import docspell.backend.ops.OCustomFields.SetValueResult
import docspell.common._
import docspell.store.AddResult
import docspell.store.Store
@ -12,20 +17,32 @@ import docspell.store.UpdateResult
import docspell.store.queries.QCustomField
import docspell.store.records.RCustomField
import docspell.store.records.RCustomFieldValue
import docspell.store.records.RItem
import doobie._
trait OCustomFields[F[_]] {
/** Find all fields using an optional query on the name and label */
def findAll(coll: Ident, nameQuery: Option[String]): F[Vector[CustomFieldData]]
/** Find one field by its id */
def findById(coll: Ident, fieldId: Ident): F[Option[CustomFieldData]]
/** Create a new non-existing field. */
def create(field: NewCustomField): F[AddResult]
/** Change an existing field. */
def change(field: RCustomField): F[UpdateResult]
/** Deletes the field by name or id. */
def delete(coll: Ident, fieldIdOrName: Ident): F[UpdateResult]
/** Sets a value given a field an an item. Existing values are overwritten. */
def setValue(item: Ident, value: SetValue): F[SetValueResult]
/** Deletes a value for a given field an item. */
def deleteValue(in: RemoveValue): F[UpdateResult]
}
object OCustomFields {
@ -40,6 +57,32 @@ object OCustomFields {
cid: Ident
)
case class SetValue(
field: Ident,
value: String,
collective: Ident
)
sealed trait SetValueResult
object SetValueResult {
case object ItemNotFound extends SetValueResult
case object FieldNotFound extends SetValueResult
case class ValueInvalid(msg: String) extends SetValueResult
case object Success extends SetValueResult
def itemNotFound: SetValueResult = ItemNotFound
def fieldNotFound: SetValueResult = FieldNotFound
def valueInvalid(msg: String): SetValueResult = ValueInvalid(msg)
def success: SetValueResult = Success
}
case class RemoveValue(
field: Ident,
item: Ident,
collective: Ident
)
def apply[F[_]: Effect](
store: Store[F]
): Resource[F, OCustomFields[F]] =
@ -76,5 +119,39 @@ object OCustomFields {
UpdateResult.fromUpdate(store.transact(update.getOrElse(0)))
}
def setValue(item: Ident, value: SetValue): F[SetValueResult] =
(for {
field <- EitherT.fromOptionF(
store.transact(RCustomField.findByIdOrName(value.field, value.collective)),
SetValueResult.fieldNotFound
)
_ <- EitherT(
store
.transact(RItem.existsByIdAndCollective(item, value.collective))
.map(flag => if (flag) Right(()) else Left(SetValueResult.itemNotFound))
)
fval <- EitherT.fromEither[F](
field.ftype
.parseValue(value.value)
.leftMap(SetValueResult.valueInvalid)
.map(field.ftype.valueString)
)
nu <- EitherT.right[SetValueResult](
store.transact(RCustomField.setValue(field, item, fval))
)
} yield nu).fold(identity, _ => SetValueResult.success)
def deleteValue(in: RemoveValue): F[UpdateResult] = {
val update =
for {
field <- OptionT(RCustomField.findByIdOrName(in.field, in.collective))
n <- OptionT.liftF(RCustomFieldValue.deleteValue(field.id, in.item))
} yield n
UpdateResult.fromUpdate(store.transact(update.getOrElse(0)))
}
})
}