mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-25 16:45:05 +00:00
Allow simple search when listing meta data
This commit is contained in:
parent
eb6c483ef0
commit
8814de3c38
@ -8,7 +8,7 @@ import docspell.store.records.{REquipment, RItem}
|
||||
|
||||
trait OEquipment[F[_]] {
|
||||
|
||||
def findAll(account: AccountId): F[Vector[REquipment]]
|
||||
def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[REquipment]]
|
||||
|
||||
def add(s: REquipment): F[AddResult]
|
||||
|
||||
@ -21,8 +21,8 @@ object OEquipment {
|
||||
|
||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OEquipment[F]] =
|
||||
Resource.pure(new OEquipment[F] {
|
||||
def findAll(account: AccountId): F[Vector[REquipment]] =
|
||||
store.transact(REquipment.findAll(account.collective, _.name))
|
||||
def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[REquipment]] =
|
||||
store.transact(REquipment.findAll(account.collective, nameQuery, _.name))
|
||||
|
||||
def add(e: REquipment): F[AddResult] = {
|
||||
def insert = REquipment.insert(e)
|
||||
|
@ -9,17 +9,17 @@ import OOrganization._
|
||||
import docspell.store.queries.QOrganization
|
||||
|
||||
trait OOrganization[F[_]] {
|
||||
def findAllOrg(account: AccountId): F[Vector[OrgAndContacts]]
|
||||
def findAllOrg(account: AccountId, query: Option[String]): F[Vector[OrgAndContacts]]
|
||||
|
||||
def findAllOrgRefs(account: AccountId): F[Vector[IdRef]]
|
||||
def findAllOrgRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]]
|
||||
|
||||
def addOrg(s: OrgAndContacts): F[AddResult]
|
||||
|
||||
def updateOrg(s: OrgAndContacts): F[AddResult]
|
||||
|
||||
def findAllPerson(account: AccountId): F[Vector[PersonAndContacts]]
|
||||
def findAllPerson(account: AccountId, query: Option[String]): F[Vector[PersonAndContacts]]
|
||||
|
||||
def findAllPersonRefs(account: AccountId): F[Vector[IdRef]]
|
||||
def findAllPersonRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]]
|
||||
|
||||
def addPerson(s: PersonAndContacts): F[AddResult]
|
||||
|
||||
@ -39,15 +39,15 @@ object OOrganization {
|
||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OOrganization[F]] =
|
||||
Resource.pure(new OOrganization[F] {
|
||||
|
||||
def findAllOrg(account: AccountId): F[Vector[OrgAndContacts]] =
|
||||
def findAllOrg(account: AccountId, query: Option[String]): F[Vector[OrgAndContacts]] =
|
||||
store
|
||||
.transact(QOrganization.findOrgAndContact(account.collective, _.name))
|
||||
.transact(QOrganization.findOrgAndContact(account.collective, query, _.name))
|
||||
.map({ case (org, cont) => OrgAndContacts(org, cont) })
|
||||
.compile
|
||||
.toVector
|
||||
|
||||
def findAllOrgRefs(account: AccountId): F[Vector[IdRef]] =
|
||||
store.transact(ROrganization.findAllRef(account.collective, _.name))
|
||||
def findAllOrgRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]] =
|
||||
store.transact(ROrganization.findAllRef(account.collective, nameQuery, _.name))
|
||||
|
||||
def addOrg(s: OrgAndContacts): F[AddResult] =
|
||||
QOrganization.addOrg(s.org, s.contacts, s.org.cid)(store)
|
||||
@ -55,15 +55,15 @@ object OOrganization {
|
||||
def updateOrg(s: OrgAndContacts): F[AddResult] =
|
||||
QOrganization.updateOrg(s.org, s.contacts, s.org.cid)(store)
|
||||
|
||||
def findAllPerson(account: AccountId): F[Vector[PersonAndContacts]] =
|
||||
def findAllPerson(account: AccountId, query: Option[String]): F[Vector[PersonAndContacts]] =
|
||||
store
|
||||
.transact(QOrganization.findPersonAndContact(account.collective, _.name))
|
||||
.transact(QOrganization.findPersonAndContact(account.collective, query, _.name))
|
||||
.map({ case (person, cont) => PersonAndContacts(person, cont) })
|
||||
.compile
|
||||
.toVector
|
||||
|
||||
def findAllPersonRefs(account: AccountId): F[Vector[IdRef]] =
|
||||
store.transact(RPerson.findAllRef(account.collective, _.name))
|
||||
def findAllPersonRefs(account: AccountId, nameQuery: Option[String]): F[Vector[IdRef]] =
|
||||
store.transact(RPerson.findAllRef(account.collective, nameQuery, _.name))
|
||||
|
||||
def addPerson(s: PersonAndContacts): F[AddResult] =
|
||||
QOrganization.addPerson(s.person, s.contacts, s.person.cid)(store)
|
||||
|
@ -8,7 +8,7 @@ import docspell.store.records.{RTag, RTagItem}
|
||||
|
||||
trait OTag[F[_]] {
|
||||
|
||||
def findAll(account: AccountId): F[Vector[RTag]]
|
||||
def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[RTag]]
|
||||
|
||||
def add(s: RTag): F[AddResult]
|
||||
|
||||
@ -21,8 +21,8 @@ object OTag {
|
||||
|
||||
def apply[F[_]: Effect](store: Store[F]): Resource[F, OTag[F]] =
|
||||
Resource.pure(new OTag[F] {
|
||||
def findAll(account: AccountId): F[Vector[RTag]] =
|
||||
store.transact(RTag.findAll(account.collective, _.name))
|
||||
def findAll(account: AccountId, nameQuery: Option[String]): F[Vector[RTag]] =
|
||||
store.transact(RTag.findAll(account.collective, nameQuery, _.name))
|
||||
|
||||
def add(t: RTag): F[AddResult] = {
|
||||
def insert = RTag.insert(t)
|
||||
|
@ -3,14 +3,17 @@ package docspell.common
|
||||
import java.security.SecureRandom
|
||||
import java.util.UUID
|
||||
|
||||
import cats.Eq
|
||||
import cats.implicits._
|
||||
import cats.effect.Sync
|
||||
import io.circe.{Decoder, Encoder}
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
case class Ident(id: String) {
|
||||
}
|
||||
case class Ident(id: String) {}
|
||||
|
||||
object Ident {
|
||||
implicit val identEq: Eq[Ident] =
|
||||
Eq.by(_.id)
|
||||
|
||||
val chars: Set[Char] = (('A' to 'Z') ++ ('a' to 'z') ++ ('0' to '9') ++ "-_").toSet
|
||||
|
||||
@ -46,8 +49,6 @@ object Ident {
|
||||
def unapply(arg: String): Option[Ident] =
|
||||
fromString(arg).toOption
|
||||
|
||||
|
||||
|
||||
implicit val encodeIdent: Encoder[Ident] =
|
||||
Encoder.encodeString.contramap(_.id)
|
||||
|
||||
|
@ -255,6 +255,8 @@ paths:
|
||||
Return a list of all configured tags.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/q"
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
@ -329,6 +331,7 @@ paths:
|
||||
- authTokenHeader: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/full"
|
||||
- $ref: "#/components/parameters/q"
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
@ -421,6 +424,7 @@ paths:
|
||||
- authTokenHeader: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/full"
|
||||
- $ref: "#/components/parameters/q"
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
@ -511,6 +515,8 @@ paths:
|
||||
Return a list of all configured equipments.
|
||||
security:
|
||||
- authTokenHeader: []
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/q"
|
||||
responses:
|
||||
200:
|
||||
description: Ok
|
||||
@ -2169,3 +2175,10 @@ components:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
q:
|
||||
name: q
|
||||
in: query
|
||||
description: A query string.
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
|
@ -19,9 +19,10 @@ object EquipmentRoutes {
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root =>
|
||||
case req @ GET -> Root =>
|
||||
val q = req.params.get("q").map(_.trim).filter(_.nonEmpty)
|
||||
for {
|
||||
data <- backend.equipment.findAll(user.account)
|
||||
data <- backend.equipment.findAll(user.account, q)
|
||||
resp <- Ok(EquipmentList(data.map(mkEquipment).toList))
|
||||
} yield resp
|
||||
|
||||
|
@ -20,15 +20,16 @@ object OrganizationRoutes {
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root :? FullQueryParamMatcher(full) =>
|
||||
case req @ GET -> Root :? FullQueryParamMatcher(full) =>
|
||||
val q = req.params.get("q").map(_.trim).filter(_.nonEmpty)
|
||||
if (full.getOrElse(false)) {
|
||||
for {
|
||||
data <- backend.organization.findAllOrg(user.account)
|
||||
data <- backend.organization.findAllOrg(user.account, q)
|
||||
resp <- Ok(OrganizationList(data.map(mkOrg).toList))
|
||||
} yield resp
|
||||
} else {
|
||||
for {
|
||||
data <- backend.organization.findAllOrgRefs(user.account)
|
||||
data <- backend.organization.findAllOrgRefs(user.account, q)
|
||||
resp <- Ok(ReferenceList(data.map(mkIdName).toList))
|
||||
} yield resp
|
||||
}
|
||||
|
@ -23,15 +23,16 @@ object PersonRoutes {
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root :? FullQueryParamMatcher(full) =>
|
||||
case req @ GET -> Root :? FullQueryParamMatcher(full) =>
|
||||
val q = req.params.get("q").map(_.trim).filter(_.nonEmpty)
|
||||
if (full.getOrElse(false)) {
|
||||
for {
|
||||
data <- backend.organization.findAllPerson(user.account)
|
||||
data <- backend.organization.findAllPerson(user.account, q)
|
||||
resp <- Ok(PersonList(data.map(mkPerson).toList))
|
||||
} yield resp
|
||||
} else {
|
||||
for {
|
||||
data <- backend.organization.findAllPersonRefs(user.account)
|
||||
data <- backend.organization.findAllPersonRefs(user.account, q)
|
||||
resp <- Ok(ReferenceList(data.map(mkIdName).toList))
|
||||
} yield resp
|
||||
}
|
||||
|
@ -20,9 +20,10 @@ object TagRoutes {
|
||||
import dsl._
|
||||
|
||||
HttpRoutes.of {
|
||||
case GET -> Root =>
|
||||
case req @ GET -> Root =>
|
||||
val q = req.params.get("q").map(_.trim).filter(_.nonEmpty)
|
||||
for {
|
||||
all <- backend.tag.findAll(user.account)
|
||||
all <- backend.tag.findAll(user.account, q)
|
||||
resp <- Ok(TagList(all.size, all.map(mkTag).toList))
|
||||
} yield resp
|
||||
|
||||
|
@ -3,9 +3,11 @@ package docspell.store.queries
|
||||
import fs2._
|
||||
import cats.implicits._
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import docspell.common._
|
||||
import docspell.store.{AddResult, Store}
|
||||
import docspell.store.impl.Column
|
||||
import docspell.store.impl.Implicits._
|
||||
import docspell.store.records.ROrganization.{Columns => OC}
|
||||
import docspell.store.records.RPerson.{Columns => PC}
|
||||
import docspell.store.records._
|
||||
@ -14,16 +16,75 @@ object QOrganization {
|
||||
|
||||
def findOrgAndContact(
|
||||
coll: Ident,
|
||||
query: Option[String],
|
||||
order: OC.type => Column
|
||||
): Stream[ConnectionIO, (ROrganization, Vector[RContact])] =
|
||||
ROrganization
|
||||
.findAll(coll, order)
|
||||
.evalMap(ro => RContact.findAllOrg(ro.oid).map(cs => (ro, cs)))
|
||||
): Stream[ConnectionIO, (ROrganization, Vector[RContact])] = {
|
||||
val oColl = ROrganization.Columns.cid.prefix("o")
|
||||
val oName = ROrganization.Columns.name.prefix("o")
|
||||
val oNotes = ROrganization.Columns.notes.prefix("o")
|
||||
val oId = ROrganization.Columns.oid.prefix("o")
|
||||
val cOrg = RContact.Columns.orgId.prefix("c")
|
||||
val cVal = RContact.Columns.value.prefix("c")
|
||||
|
||||
val cols = ROrganization.Columns.all.map(_.prefix("o")) ++ RContact.Columns.all
|
||||
.map(_.prefix("c"))
|
||||
val from = ROrganization.table ++ fr"o LEFT JOIN" ++
|
||||
RContact.table ++ fr"c ON" ++ cOrg.is(oId)
|
||||
|
||||
val q = Seq(oColl.is(coll)) ++ (query match {
|
||||
case Some(str) =>
|
||||
val v = s"%$str%"
|
||||
Seq(or(cVal.lowerLike(v), oName.lowerLike(v), oNotes.lowerLike(v)))
|
||||
case None =>
|
||||
Seq.empty
|
||||
})
|
||||
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(OC).f))
|
||||
.query[(ROrganization, Option[RContact])]
|
||||
.stream
|
||||
.groupAdjacentBy(_._1)
|
||||
.map({
|
||||
case (ro, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._2)
|
||||
(ro, cs)
|
||||
})
|
||||
}
|
||||
|
||||
def findPersonAndContact(
|
||||
coll: Ident,
|
||||
query: Option[String],
|
||||
order: PC.type => Column
|
||||
): Stream[ConnectionIO, (RPerson, Vector[RContact])] =
|
||||
RPerson.findAll(coll, order).evalMap(ro => RContact.findAllPerson(ro.pid).map(cs => (ro, cs)))
|
||||
): Stream[ConnectionIO, (RPerson, Vector[RContact])] = {
|
||||
val pColl = PC.cid.prefix("p")
|
||||
val pName = RPerson.Columns.name.prefix("p")
|
||||
val pNotes = RPerson.Columns.notes.prefix("p")
|
||||
val pId = RPerson.Columns.pid.prefix("p")
|
||||
val cPers = RContact.Columns.personId.prefix("c")
|
||||
val cVal = RContact.Columns.value.prefix("c")
|
||||
|
||||
val cols = RPerson.Columns.all.map(_.prefix("p")) ++ RContact.Columns.all
|
||||
.map(_.prefix("c"))
|
||||
val from = RPerson.table ++ fr"p LEFT JOIN" ++
|
||||
RContact.table ++ fr"c ON" ++ cPers.is(pId)
|
||||
|
||||
val q = Seq(pColl.is(coll)) ++ (query match {
|
||||
case Some(str) =>
|
||||
val v = s"%${str.toLowerCase}%"
|
||||
Seq(or(cVal.lowerLike(v), pName.lowerLike(v), pNotes.lowerLike(v)))
|
||||
case None =>
|
||||
Seq.empty
|
||||
})
|
||||
|
||||
(selectSimple(cols, from, and(q)) ++ orderBy(order(PC).f))
|
||||
.query[(RPerson, Option[RContact])]
|
||||
.stream
|
||||
.groupAdjacentBy(_._1)
|
||||
.map({
|
||||
case (ro, chunk) =>
|
||||
val cs = chunk.toVector.flatMap(_._2)
|
||||
(ro, cs)
|
||||
})
|
||||
}
|
||||
|
||||
def addOrg[F[_]](
|
||||
org: ROrganization,
|
||||
|
@ -47,8 +47,16 @@ object REquipment {
|
||||
sql.query[REquipment].option
|
||||
}
|
||||
|
||||
def findAll(coll: Ident, order: Columns.type => Column): ConnectionIO[Vector[REquipment]] = {
|
||||
val sql = selectSimple(all, table, cid.is(coll)) ++ orderBy(order(Columns).f)
|
||||
def findAll(
|
||||
coll: Ident,
|
||||
nameQ: Option[String],
|
||||
order: Columns.type => Column
|
||||
): ConnectionIO[Vector[REquipment]] = {
|
||||
val q = Seq(cid.is(coll)) ++ (nameQ match {
|
||||
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
|
||||
case None => Seq.empty
|
||||
})
|
||||
val sql = selectSimple(all, table, and(q)) ++ orderBy(order(Columns).f)
|
||||
sql.query[REquipment].to[Vector]
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
package docspell.store.records
|
||||
|
||||
import cats.Eq
|
||||
import fs2.Stream
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
@ -20,6 +21,8 @@ case class ROrganization(
|
||||
) {}
|
||||
|
||||
object ROrganization {
|
||||
implicit val orgEq: Eq[ROrganization] =
|
||||
Eq.by[ROrganization, Ident](_.oid)
|
||||
|
||||
val table = fr"organization"
|
||||
|
||||
@ -105,8 +108,16 @@ object ROrganization {
|
||||
sql.query[ROrganization].stream
|
||||
}
|
||||
|
||||
def findAllRef(coll: Ident, order: Columns.type => Column): ConnectionIO[Vector[IdRef]] = {
|
||||
val sql = selectSimple(List(oid, name), table, cid.is(coll)) ++ orderBy(order(Columns).f)
|
||||
def findAllRef(
|
||||
coll: Ident,
|
||||
nameQ: Option[String],
|
||||
order: Columns.type => Column
|
||||
): ConnectionIO[Vector[IdRef]] = {
|
||||
val q = Seq(cid.is(coll)) ++ (nameQ match {
|
||||
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
|
||||
case None => Seq.empty
|
||||
})
|
||||
val sql = selectSimple(List(oid, name), table, and(q)) ++ orderBy(order(Columns).f)
|
||||
sql.query[IdRef].to[Vector]
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package docspell.store.records
|
||||
|
||||
import fs2.Stream
|
||||
import cats.Eq
|
||||
import doobie._
|
||||
import doobie.implicits._
|
||||
import docspell.common.{IdRef, _}
|
||||
@ -21,6 +22,8 @@ case class RPerson(
|
||||
) {}
|
||||
|
||||
object RPerson {
|
||||
implicit val personEq: Eq[RPerson] =
|
||||
Eq.by(_.pid)
|
||||
|
||||
val table = fr"person"
|
||||
|
||||
@ -116,8 +119,16 @@ object RPerson {
|
||||
sql.query[RPerson].stream
|
||||
}
|
||||
|
||||
def findAllRef(coll: Ident, order: Columns.type => Column): ConnectionIO[Vector[IdRef]] = {
|
||||
val sql = selectSimple(List(pid, name), table, cid.is(coll)) ++ orderBy(order(Columns).f)
|
||||
def findAllRef(
|
||||
coll: Ident,
|
||||
nameQ: Option[String],
|
||||
order: Columns.type => Column
|
||||
): ConnectionIO[Vector[IdRef]] = {
|
||||
val q = Seq(cid.is(coll)) ++ (nameQ match {
|
||||
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
|
||||
case None => Seq.empty
|
||||
})
|
||||
val sql = selectSimple(List(pid, name), table, and(q)) ++ orderBy(order(Columns).f)
|
||||
sql.query[IdRef].to[Vector]
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,16 @@ object RTag {
|
||||
sql.query[Int].unique.map(_ > 0)
|
||||
}
|
||||
|
||||
def findAll(coll: Ident, order: Columns.type => Column): ConnectionIO[Vector[RTag]] = {
|
||||
val sql = selectSimple(all, table, cid.is(coll)) ++ orderBy(order(Columns).f)
|
||||
def findAll(
|
||||
coll: Ident,
|
||||
nameQ: Option[String],
|
||||
order: Columns.type => Column
|
||||
): ConnectionIO[Vector[RTag]] = {
|
||||
val q = Seq(cid.is(coll)) ++ (nameQ match {
|
||||
case Some(str) => Seq(name.lowerLike(s"%${str.toLowerCase}%"))
|
||||
case None => Seq.empty
|
||||
})
|
||||
val sql = selectSimple(all, table, and(q)) ++ orderBy(order(Columns).f)
|
||||
sql.query[RTag].to[Vector]
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user