mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-02 13:32:51 +00:00
Allow client to load items in batches
This commit is contained in:
parent
062618bf86
commit
e5b90eff34
@ -12,6 +12,7 @@ import OItem.{
|
||||
AttachmentArchiveData,
|
||||
AttachmentData,
|
||||
AttachmentSourceData,
|
||||
Batch,
|
||||
ItemData,
|
||||
ListItem,
|
||||
Query
|
||||
@ -24,7 +25,7 @@ trait OItem[F[_]] {
|
||||
|
||||
def findItem(id: Ident, collective: Ident): F[Option[ItemData]]
|
||||
|
||||
def findItems(q: Query, maxResults: Int): F[Vector[ListItem]]
|
||||
def findItems(q: Query, batch: Batch): F[Vector[ListItem]]
|
||||
|
||||
def findAttachment(id: Ident, collective: Ident): F[Option[AttachmentData[F]]]
|
||||
|
||||
@ -84,6 +85,9 @@ object OItem {
|
||||
type Query = QItem.Query
|
||||
val Query = QItem.Query
|
||||
|
||||
type Batch = QItem.Batch
|
||||
val Batch = QItem.Batch
|
||||
|
||||
type ListItem = QItem.ListItem
|
||||
val ListItem = QItem.ListItem
|
||||
|
||||
@ -138,8 +142,11 @@ object OItem {
|
||||
.transact(QItem.findItem(id))
|
||||
.map(opt => opt.flatMap(_.filterCollective(collective)))
|
||||
|
||||
def findItems(q: Query, maxResults: Int): F[Vector[ListItem]] =
|
||||
store.transact(QItem.findItems(q).take(maxResults.toLong)).compile.toVector
|
||||
def findItems(q: Query, batch: Batch): F[Vector[ListItem]] =
|
||||
store
|
||||
.transact(QItem.findItems(q, batch).take(batch.limit.toLong))
|
||||
.compile
|
||||
.toVector
|
||||
|
||||
def findAttachment(id: Ident, collective: Ident): F[Option[AttachmentData[F]]] =
|
||||
store
|
||||
|
@ -8,6 +8,7 @@ import emil.markdown._
|
||||
import emil.javamail.syntax._
|
||||
|
||||
import docspell.common._
|
||||
import docspell.backend.ops.OItem.Batch
|
||||
import docspell.store.records._
|
||||
import docspell.store.queries.QItem
|
||||
import docspell.joex.scheduler.{Context, Task}
|
||||
@ -15,7 +16,7 @@ import cats.data.OptionT
|
||||
import docspell.joex.mail.EmilHeader
|
||||
|
||||
object NotifyDueItemsTask {
|
||||
val maxItems: Long = 7
|
||||
val maxItems: Int = 7
|
||||
type Args = NotifyDueItemsArgs
|
||||
|
||||
def apply[F[_]: Sync](cfg: MailSendConfig, emil: Emil[F]): Task[F, Args, Unit] =
|
||||
@ -78,7 +79,11 @@ object NotifyDueItemsTask {
|
||||
dueDateTo = Some(now + Duration.days(ctx.args.remindDays.toLong)),
|
||||
orderAsc = Some(_.dueDate)
|
||||
)
|
||||
res <- ctx.store.transact(QItem.findItems(q).take(maxItems)).compile.toVector
|
||||
res <-
|
||||
ctx.store
|
||||
.transact(QItem.findItems(q, Batch.limit(maxItems)).take(maxItems.toLong))
|
||||
.compile
|
||||
.toVector
|
||||
} yield res
|
||||
|
||||
def makeMail[F[_]: Sync](
|
||||
|
@ -3121,6 +3121,8 @@ components:
|
||||
- tagsInclude
|
||||
- tagsExclude
|
||||
- inbox
|
||||
- offset
|
||||
- limit
|
||||
properties:
|
||||
tagsInclude:
|
||||
type: array
|
||||
@ -3134,6 +3136,16 @@ components:
|
||||
format: ident
|
||||
inbox:
|
||||
type: boolean
|
||||
offset:
|
||||
type: integer
|
||||
format: int32
|
||||
limit:
|
||||
type: integer
|
||||
format: int32
|
||||
description: |
|
||||
The maximum number of results to return. Note that this
|
||||
limit is a soft limit, there is some hard limit on the
|
||||
server, too.
|
||||
direction:
|
||||
type: string
|
||||
format: direction
|
||||
|
@ -4,6 +4,7 @@ import cats.effect._
|
||||
import cats.implicits._
|
||||
import docspell.backend.BackendApp
|
||||
import docspell.backend.auth.AuthToken
|
||||
import docspell.backend.ops.OItem.Batch
|
||||
import docspell.common.{Ident, ItemState}
|
||||
import org.http4s.HttpRoutes
|
||||
import org.http4s.dsl.Http4sDsl
|
||||
@ -27,9 +28,12 @@ object ItemRoutes {
|
||||
mask <- req.as[ItemSearch]
|
||||
_ <- logger.ftrace(s"Got search mask: $mask")
|
||||
query = Conversions.mkQuery(mask, user.account.collective)
|
||||
_ <- logger.ftrace(s"Running query: $query")
|
||||
items <- backend.item.findItems(query, 100)
|
||||
resp <- Ok(Conversions.mkItemList(items))
|
||||
_ <- logger.ftrace(s"Running query: $query")
|
||||
items <- backend.item.findItems(
|
||||
query,
|
||||
Batch(mask.offset, mask.limit).restrictLimitTo(500)
|
||||
)
|
||||
resp <- Ok(Conversions.mkItemList(items))
|
||||
} yield resp
|
||||
|
||||
case GET -> Root / Ident(id) =>
|
||||
|
@ -187,7 +187,22 @@ object QItem {
|
||||
)
|
||||
}
|
||||
|
||||
def findItems(q: Query): Stream[ConnectionIO, ListItem] = {
|
||||
case class Batch(offset: Int, limit: Int) {
|
||||
def restrictLimitTo(n: Int): Batch =
|
||||
Batch(offset, math.min(n, limit))
|
||||
}
|
||||
|
||||
object Batch {
|
||||
val all: Batch = Batch(0, Int.MaxValue)
|
||||
|
||||
def page(n: Int, size: Int): Batch =
|
||||
Batch(n * size, size)
|
||||
|
||||
def limit(c: Int): Batch =
|
||||
Batch(0, c)
|
||||
}
|
||||
|
||||
def findItems(q: Query, batch: Batch): Stream[ConnectionIO, ListItem] = {
|
||||
val IC = RItem.Columns
|
||||
val AC = RAttachment.Columns
|
||||
val PC = RPerson.Columns
|
||||
@ -202,7 +217,7 @@ object QItem {
|
||||
IC.id.prefix("i").f,
|
||||
IC.name.prefix("i").f,
|
||||
IC.state.prefix("i").f,
|
||||
coalesce(IC.itemDate.prefix("i").f, IC.created.prefix("i").f),
|
||||
coalesce(IC.itemDate.prefix("i").f, IC.created.prefix("i").f) ++ fr"i_date",
|
||||
IC.dueDate.prefix("i").f,
|
||||
IC.source.prefix("i").f,
|
||||
IC.incoming.prefix("i").f,
|
||||
@ -310,11 +325,12 @@ object QItem {
|
||||
case Some(co) =>
|
||||
orderBy(coalesce(co(IC).prefix("i").f, IC.created.prefix("i").f) ++ fr"ASC")
|
||||
case None =>
|
||||
orderBy(
|
||||
coalesce(IC.itemDate.prefix("i").f, IC.created.prefix("i").f) ++ fr"DESC"
|
||||
)
|
||||
orderBy(fr"i_date DESC")
|
||||
}
|
||||
val frag = query ++ fr"WHERE" ++ cond ++ order
|
||||
val frag =
|
||||
query ++ fr"WHERE" ++ cond ++ order ++ (if (batch == Batch.all) Fragment.empty
|
||||
else
|
||||
fr"OFFSET ${batch.offset} LIMIT ${batch.limit}")
|
||||
logger.trace(s"List items: $frag")
|
||||
frag.query[ListItem].stream
|
||||
}
|
||||
|
@ -77,8 +77,11 @@ update key flags msg model =
|
||||
doSearch : Flags -> Model -> ( Model, Cmd Msg )
|
||||
doSearch flags model =
|
||||
let
|
||||
mask =
|
||||
smask =
|
||||
Comp.SearchMenu.getItemSearch model.searchMenuModel
|
||||
|
||||
mask =
|
||||
{ smask | limit = 100 }
|
||||
in
|
||||
( { model | searchInProgress = True, viewMode = Listing }
|
||||
, Api.itemSearch flags mask ItemSearchResp
|
||||
|
Loading…
x
Reference in New Issue
Block a user