Add a use colum to metadata entities

This commit is contained in:
Eike Kettner 2021-03-10 22:16:04 +01:00
parent 1a188afbd7
commit 0229a867af
13 changed files with 223 additions and 22 deletions

View File

@ -0,0 +1,46 @@
package docspell.common
import cats.data.NonEmptyList
import io.circe.Decoder
import io.circe.Encoder
sealed trait EquipmentUse { self: Product =>
final def name: String =
self.productPrefix.toLowerCase()
}
object EquipmentUse {
case object Concerning extends EquipmentUse
case object Disabled extends EquipmentUse
def concerning: EquipmentUse = Concerning
def disabled: EquipmentUse = Disabled
val all: NonEmptyList[EquipmentUse] =
NonEmptyList.of(concerning, disabled)
val notDisabled: NonEmptyList[EquipmentUse] =
NonEmptyList.of(concerning)
def fromString(str: String): Either[String, EquipmentUse] =
str.toLowerCase() match {
case "concerning" =>
Right(Concerning)
case "disabled" =>
Right(Disabled)
case _ =>
Left(s"Unknown equipment-use: $str")
}
def unsafeFromString(str: String): EquipmentUse =
fromString(str).fold(sys.error, identity)
implicit val jsonDecoder: Decoder[EquipmentUse] =
Decoder.decodeString.emap(fromString)
implicit val jsonEncoder: Encoder[EquipmentUse] =
Encoder.encodeString.contramap(_.name)
}

View File

@ -0,0 +1,46 @@
package docspell.common
import cats.data.NonEmptyList
import io.circe.Decoder
import io.circe.Encoder
sealed trait OrgUse { self: Product =>
final def name: String =
self.productPrefix.toLowerCase()
}
object OrgUse {
case object Correspondent extends OrgUse
case object Disabled extends OrgUse
def correspondent: OrgUse = Correspondent
def disabled: OrgUse = Disabled
val all: NonEmptyList[OrgUse] =
NonEmptyList.of(correspondent, disabled)
val notDisabled: NonEmptyList[OrgUse] =
NonEmptyList.of(correspondent)
def fromString(str: String): Either[String, OrgUse] =
str.toLowerCase() match {
case "correspondent" =>
Right(Correspondent)
case "disabled" =>
Right(Disabled)
case _ =>
Left(s"Unknown organization-use: $str")
}
def unsafeFromString(str: String): OrgUse =
fromString(str).fold(sys.error, identity)
implicit val jsonDecoder: Decoder[OrgUse] =
Decoder.decodeString.emap(fromString)
implicit val jsonEncoder: Encoder[OrgUse] =
Encoder.encodeString.contramap(_.name)
}

View File

@ -16,6 +16,7 @@ object PersonUse {
case object Correspondent extends PersonUse case object Correspondent extends PersonUse
case object Concerning extends PersonUse case object Concerning extends PersonUse
case object Both extends PersonUse case object Both extends PersonUse
case object Disabled extends PersonUse
def concerning: PersonUse = Concerning def concerning: PersonUse = Concerning
def correspondent: PersonUse = Correspondent def correspondent: PersonUse = Correspondent
@ -35,6 +36,8 @@ object PersonUse {
Right(Concerning) Right(Concerning)
case "both" => case "both" =>
Right(Both) Right(Both)
case "disabled" =>
Right(Disabled)
case _ => case _ =>
Left(s"Unknown person-use: $str") Left(s"Unknown person-use: $str")
} }

View File

@ -47,7 +47,7 @@ object FindProposal {
ctx.store ctx.store
.transact( .transact(
ROrganization ROrganization
.findLike(coll, mp.values.head.ref.name.toLowerCase) .findLike(coll, mp.values.head.ref.name.toLowerCase, OrgUse.notDisabled)
.map(_.headOption) .map(_.headOption)
) )
.flatTap(oref => .flatTap(oref =>
@ -85,7 +85,11 @@ object FindProposal {
ctx.store ctx.store
.transact( .transact(
REquipment REquipment
.findLike(coll, mp.values.head.ref.name.toLowerCase) .findLike(
coll,
mp.values.head.ref.name.toLowerCase,
EquipmentUse.notDisabled
)
.map(_.headOption) .map(_.headOption)
) )
.flatTap(oref => .flatTap(oref =>
@ -234,7 +238,10 @@ object FindProposal {
case NerTag.Organization => case NerTag.Organization =>
ctx.logger.debug(s"Looking for organizations: $value") *> ctx.logger.debug(s"Looking for organizations: $value") *>
ctx.store ctx.store
.transact(ROrganization.findLike(ctx.args.meta.collective, value)) .transact(
ROrganization
.findLike(ctx.args.meta.collective, value, OrgUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.CorrOrg, nt)) .map(MetaProposalList.from(MetaProposalType.CorrOrg, nt))
case NerTag.Person => case NerTag.Person =>
@ -252,7 +259,10 @@ object FindProposal {
.map(MetaProposalList.from(MetaProposalType.CorrPerson, nt)) .map(MetaProposalList.from(MetaProposalType.CorrPerson, nt))
val s3 = val s3 =
ctx.store ctx.store
.transact(ROrganization.findLike(ctx.args.meta.collective, value)) .transact(
ROrganization
.findLike(ctx.args.meta.collective, value, OrgUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.CorrOrg, nt)) .map(MetaProposalList.from(MetaProposalType.CorrOrg, nt))
ctx.logger.debug(s"Looking for persons and organizations: $value") *> (for { ctx.logger.debug(s"Looking for persons and organizations: $value") *> (for {
ml0 <- s1 ml0 <- s1
@ -268,7 +278,10 @@ object FindProposal {
case NerTag.Misc => case NerTag.Misc =>
ctx.logger.debug(s"Looking for equipments: $value") *> ctx.logger.debug(s"Looking for equipments: $value") *>
ctx.store ctx.store
.transact(REquipment.findLike(ctx.args.meta.collective, value)) .transact(
REquipment
.findLike(ctx.args.meta.collective, value, EquipmentUse.notDisabled)
)
.map(MetaProposalList.from(MetaProposalType.ConcEquip, nt)) .map(MetaProposalList.from(MetaProposalType.ConcEquip, nt))
case NerTag.Email => case NerTag.Email =>

View File

@ -414,7 +414,8 @@ trait Conversions {
v.notes, v.notes,
now, now,
now, now,
v.shortName.map(_.trim) v.shortName.map(_.trim),
OrgUse.Correspondent
) )
} yield OOrganization.OrgAndContacts(org, cont) } yield OOrganization.OrgAndContacts(org, cont)
} }
@ -439,7 +440,8 @@ trait Conversions {
v.notes, v.notes,
v.created, v.created,
now, now,
v.shortName.map(_.trim) v.shortName.map(_.trim),
OrgUse.Correspondent
) )
} yield OOrganization.OrgAndContacts(org, cont) } yield OOrganization.OrgAndContacts(org, cont)
} }
@ -632,13 +634,13 @@ trait Conversions {
def newEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] = def newEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
timeId.map({ case (id, now) => timeId.map({ case (id, now) =>
REquipment(id, cid, e.name.trim, now, now, e.notes) REquipment(id, cid, e.name.trim, now, now, e.notes, EquipmentUse.Concerning)
}) })
def changeEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] = def changeEquipment[F[_]: Sync](e: Equipment, cid: Ident): F[REquipment] =
Timestamp Timestamp
.current[F] .current[F]
.map(now => REquipment(e.id, cid, e.name.trim, e.created, now, e.notes)) .map(now => REquipment(e.id, cid, e.name.trim, e.created, now, e.notes, EquipmentUse.Concerning))
// idref // idref

View File

@ -0,0 +1,16 @@
ALTER TABLE "equipment"
ADD COLUMN "equip_use" varchar(254);
UPDATE "equipment" SET "equip_use" = 'concerning';
ALTER TABLE "equipment"
ALTER COLUMN "equip_use" SET NOT NULL;
ALTER TABLE "organization"
ADD COLUMN "org_use" varchar(254);
UPDATE "organization" SET "org_use" = 'correspondent';
ALTER TABLE "organization"
ALTER COLUMN "org_use" SET NOT NULL;

View File

@ -0,0 +1,16 @@
ALTER TABLE `equipment`
ADD COLUMN `equip_use` varchar(254);
UPDATE `equipment` SET `equip_use` = 'concerning';
ALTER TABLE `equipment`
ALTER COLUMN `equip_use` SET NOT NULL;
ALTER TABLE `organization`
ADD COLUMN `org_use` varchar(254);
UPDATE `organization` SET `org_use` = 'correspondent';
ALTER TABLE `organization`
ALTER COLUMN `org_use` SET NOT NULL;

View File

@ -0,0 +1,16 @@
ALTER TABLE "equipment"
ADD COLUMN "equip_use" varchar(254);
UPDATE "equipment" SET "equip_use" = 'concerning';
ALTER TABLE "equipment"
ALTER COLUMN "equip_use" SET NOT NULL;
ALTER TABLE "organization"
ADD COLUMN "org_use" varchar(254);
UPDATE "organization" SET "org_use" = 'correspondent';
ALTER TABLE "organization"
ALTER COLUMN "org_use" SET NOT NULL;

View File

@ -106,6 +106,12 @@ trait DoobieMeta extends EmilDoobieMeta {
implicit val metaPersonUse: Meta[PersonUse] = implicit val metaPersonUse: Meta[PersonUse] =
Meta[String].timap(PersonUse.unsafeFromString)(_.name) Meta[String].timap(PersonUse.unsafeFromString)(_.name)
implicit val metaEquipUse: Meta[EquipmentUse] =
Meta[String].timap(EquipmentUse.unsafeFromString)(_.name)
implicit val metaOrgUse: Meta[OrgUse] =
Meta[String].timap(OrgUse.unsafeFromString)(_.name)
} }
object DoobieMeta extends DoobieMeta { object DoobieMeta extends DoobieMeta {

View File

@ -15,7 +15,8 @@ case class REquipment(
name: String, name: String,
created: Timestamp, created: Timestamp,
updated: Timestamp, updated: Timestamp,
notes: Option[String] notes: Option[String],
use: EquipmentUse
) {} ) {}
object REquipment { object REquipment {
@ -28,7 +29,8 @@ object REquipment {
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val updated = Column[Timestamp]("updated", this) val updated = Column[Timestamp]("updated", this)
val notes = Column[String]("notes", this) val notes = Column[String]("notes", this)
val all = NonEmptyList.of[Column[_]](eid, cid, name, created, updated, notes) val use = Column[EquipmentUse]("equip_use", this)
val all = NonEmptyList.of[Column[_]](eid, cid, name, created, updated, notes, use)
} }
val T = Table(None) val T = Table(None)
@ -41,7 +43,7 @@ object REquipment {
.insert( .insert(
t, t,
t.all, t.all,
fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated},${v.notes}" fr"${v.eid},${v.cid},${v.name},${v.created},${v.updated},${v.notes},${v.use}"
) )
} }
@ -57,7 +59,8 @@ object REquipment {
t.cid.setTo(v.cid), t.cid.setTo(v.cid),
t.name.setTo(v.name), t.name.setTo(v.name),
t.updated.setTo(now), t.updated.setTo(now),
t.notes.setTo(v.notes) t.notes.setTo(v.notes),
t.use.setTo(v.use)
) )
) )
} yield n } yield n
@ -90,9 +93,17 @@ object REquipment {
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,
use: NonEmptyList[EquipmentUse]
): ConnectionIO[Vector[IdRef]] = {
val t = Table(None) val t = Table(None)
run(select(t.eid, t.name), from(t), t.cid === coll && t.name.like(equipName)) run(
select(t.eid, t.name),
from(t),
t.cid === coll && t.name.like(equipName) && t.use.in(use)
)
.query[IdRef] .query[IdRef]
.to[Vector] .to[Vector]
} }

View File

@ -22,7 +22,8 @@ case class ROrganization(
notes: Option[String], notes: Option[String],
created: Timestamp, created: Timestamp,
updated: Timestamp, updated: Timestamp,
shortName: Option[String] shortName: Option[String],
use: OrgUse
) {} ) {}
object ROrganization { object ROrganization {
@ -43,6 +44,7 @@ object ROrganization {
val created = Column[Timestamp]("created", this) val created = Column[Timestamp]("created", this)
val updated = Column[Timestamp]("updated", this) val updated = Column[Timestamp]("updated", this)
val shortName = Column[String]("short_name", this) val shortName = Column[String]("short_name", this)
val use = Column[OrgUse]("org_use", this)
val all = val all =
NonEmptyList.of[Column[_]]( NonEmptyList.of[Column[_]](
oid, oid,
@ -55,7 +57,8 @@ object ROrganization {
notes, notes,
created, created,
updated, updated,
shortName shortName,
use
) )
} }
@ -67,7 +70,7 @@ object ROrganization {
DML.insert( DML.insert(
T, T,
T.all, T.all,
fr"${v.oid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.created},${v.updated},${v.shortName}" fr"${v.oid},${v.cid},${v.name},${v.street},${v.zip},${v.city},${v.country},${v.notes},${v.created},${v.updated},${v.shortName},${v.use}"
) )
def update(v: ROrganization): ConnectionIO[Int] = { def update(v: ROrganization): ConnectionIO[Int] = {
@ -84,7 +87,8 @@ object ROrganization {
T.country.setTo(v.country), T.country.setTo(v.country),
T.notes.setTo(v.notes), T.notes.setTo(v.notes),
T.updated.setTo(now), T.updated.setTo(now),
T.shortName.setTo(v.shortName) T.shortName.setTo(v.shortName),
T.use.setTo(v.use)
) )
) )
for { for {
@ -109,11 +113,17 @@ object ROrganization {
sql.query[ROrganization].option sql.query[ROrganization].option
} }
def findLike(coll: Ident, orgName: String): ConnectionIO[Vector[IdRef]] = def findLike(
coll: Ident,
orgName: String,
use: NonEmptyList[OrgUse]
): ConnectionIO[Vector[IdRef]] =
run( run(
select(T.oid, T.name), select(T.oid, T.name),
from(T), from(T),
T.cid === coll && (T.name.like(orgName) || T.shortName.like(orgName)) T.cid === coll && (T.name.like(orgName) || T.shortName.like(orgName)) && T.use.in(
use
)
) )
.query[IdRef] .query[IdRef]
.to[Vector] .to[Vector]

View File

@ -229,6 +229,9 @@ view2 mobile settings model =
Data.PersonUse.Both -> Data.PersonUse.Both ->
text "Use as both concerning or correspondent person" text "Use as both concerning or correspondent person"
Data.PersonUse.Disabled ->
text "Do not use for suggestions."
] ]
] ]
, div [ class "mb-4" ] , div [ class "mb-4" ]

View File

@ -14,6 +14,7 @@ type PersonUse
= Correspondent = Correspondent
| Concerning | Concerning
| Both | Both
| Disabled
fromString : String -> Maybe PersonUse fromString : String -> Maybe PersonUse
@ -28,6 +29,9 @@ fromString str =
"both" -> "both" ->
Just Both Just Both
"disabled" ->
Just Disabled
_ -> _ ->
Nothing Nothing
@ -44,6 +48,9 @@ asString pu =
Both -> Both ->
"both" "both"
Disabled ->
"disabled"
label : PersonUse -> String label : PersonUse -> String
label pu = label pu =
@ -57,10 +64,13 @@ label pu =
Both -> Both ->
"Both" "Both"
Disabled ->
"Disabled"
all : List PersonUse all : List PersonUse
all = all =
[ Correspondent, Concerning, Both ] [ Correspondent, Concerning, Both, Disabled ]
spanPersonList : List Person -> { concerning : List Person, correspondent : List Person } spanPersonList : List Person -> { concerning : List Person, correspondent : List Person }
@ -86,5 +96,8 @@ spanPersonList input =
| correspondent = p :: res.correspondent | correspondent = p :: res.correspondent
, concerning = p :: res.concerning , concerning = p :: res.concerning
} }
Disabled ->
res
in in
List.foldl merge init input List.foldl merge init input