Amend search results with attachment info

This uses again another query per item to retrieve some information
about each attachment already in the search results.
This commit is contained in:
Eike Kettner 2020-11-09 14:24:28 +01:00
parent a77f34b7ba
commit 8c08bf233d
3 changed files with 71 additions and 10 deletions

View File

@ -1291,10 +1291,11 @@ paths:
summary: Search for items.
description: |
Search for items given a search form. The results are grouped
by month and are sorted by item date (newest first). Tags are
*not* resolved. The results will always contain an empty list
for item tags. Use `/searchWithTags` to also retrieve all tags
of an item.
by month and are sorted by item date (newest first). Tags and
attachments are *not* resolved. The results will always
contain an empty list for item tags and attachments. Use
`/searchWithTags` to also retrieve all tags and a list of
attachments of an item.
The `fulltext` field can be used to restrict the results by
using full-text search in the documents contents.
@ -1318,9 +1319,10 @@ paths:
summary: Search for items.
description: |
Search for items given a search form. The results are grouped
by month by default. For each item, its tags are also
returned. This uses more queries and is therefore slower, but
returns all tags to an item.
by month by default. For each item, its tags and attachments
are also returned. This uses more queries and is therefore
slower, but returns all tags to an item as well as their
attachments with some minor details.
The `fulltext` field can be used to restrict the results by
using full-text search in the documents contents.
@ -4703,6 +4705,10 @@ components:
fileCount:
type: integer
format: int32
attachments:
type: array
items:
$ref: "#/components/schemas/AttachmentLight"
tags:
type: array
items:
@ -4720,6 +4726,24 @@ components:
type: array
items:
$ref: "#/components/schemas/HighlightEntry"
AttachmentLight:
description: |
Some little details about an attachment.
required:
- id
- position
properties:
id:
type: string
format: ident
position:
type: integer
format: int32
name:
type: string
pageCount:
type: integer
format: int32
HighlightEntry:
description: |
Highlighting information for a single field (maybe attachment

View File

@ -22,6 +22,7 @@ import bitpeace.FileMeta
import org.http4s.headers.`Content-Type`
import org.http4s.multipart.Multipart
import org.log4s.Logger
import docspell.store.queries.QItem
trait Conversions {
@ -204,6 +205,7 @@ trait Conversions {
i.folder.map(mkIdName),
i.fileCount,
Nil,
Nil,
i.notes,
Nil
)
@ -215,7 +217,11 @@ trait Conversions {
}
def mkItemLightWithTags(i: OItemSearch.ListItemWithTags): ItemLight =
mkItemLight(i.item).copy(tags = i.tags.map(mkTag))
mkItemLight(i.item)
.copy(tags = i.tags.map(mkTag), attachments = i.attachments.map(mkAttachmentLight))
private def mkAttachmentLight(qa: QItem.AttachmentLight): AttachmentLight =
AttachmentLight(qa.id, qa.position, qa.name, qa.pageCount)
def mkItemLightWithTags(i: OFulltext.FtsItemWithTags): ItemLight = {
val il = mkItemLightWithTags(i.item)

View File

@ -443,7 +443,17 @@ object QItem {
from.query[ListItem].stream
}
case class ListItemWithTags(item: ListItem, tags: List[RTag])
case class AttachmentLight(
id: Ident,
position: Int,
name: Option[String],
pageCount: Option[Int]
)
case class ListItemWithTags(
item: ListItem,
tags: List[RTag],
attachments: List[AttachmentLight]
)
/** Same as `findItems` but resolves the tags for each item. Note that
* this is implemented by running an additional query per item.
@ -476,8 +486,29 @@ object QItem {
item <- search
tagItems <- Stream.eval(RTagItem.findByItem(item.id))
tags <- Stream.eval(tagItems.traverse(ti => findTag(resolvedTags, ti)))
attachs <- Stream.eval(findAttachmentLight(item.id))
ftags = tags.flatten.filter(t => t.collective == collective)
} yield ListItemWithTags(item, ftags.toList.sortBy(_.name))
} yield ListItemWithTags(
item,
ftags.toList.sortBy(_.name),
attachs.sortBy(_.position)
)
}
private def findAttachmentLight(item: Ident): ConnectionIO[List[AttachmentLight]] = {
val aId = RAttachment.Columns.id.prefix("a")
val aItem = RAttachment.Columns.itemId.prefix("a")
val aPos = RAttachment.Columns.position.prefix("a")
val aName = RAttachment.Columns.name.prefix("a")
val mId = RAttachmentMeta.Columns.id.prefix("m")
val mPages = RAttachmentMeta.Columns.pages.prefix("m")
val cols = Seq(aId, aPos, aName, mPages)
val join = RAttachment.table ++
fr"a LEFT OUTER JOIN" ++ RAttachmentMeta.table ++ fr"m ON" ++ aId.is(mId)
val cond = aItem.is(item)
selectSimple(cols, join, cond).query[AttachmentLight].to[List]
}
def delete[F[_]: Sync](store: Store[F])(itemId: Ident, collective: Ident): F[Int] =