mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-03-25 16:45:05 +00:00
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:
parent
a77f34b7ba
commit
8c08bf233d
@ -1291,10 +1291,11 @@ paths:
|
|||||||
summary: Search for items.
|
summary: Search for items.
|
||||||
description: |
|
description: |
|
||||||
Search for items given a search form. The results are grouped
|
Search for items given a search form. The results are grouped
|
||||||
by month and are sorted by item date (newest first). Tags are
|
by month and are sorted by item date (newest first). Tags and
|
||||||
*not* resolved. The results will always contain an empty list
|
attachments are *not* resolved. The results will always
|
||||||
for item tags. Use `/searchWithTags` to also retrieve all tags
|
contain an empty list for item tags and attachments. Use
|
||||||
of an item.
|
`/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
|
The `fulltext` field can be used to restrict the results by
|
||||||
using full-text search in the documents contents.
|
using full-text search in the documents contents.
|
||||||
@ -1318,9 +1319,10 @@ paths:
|
|||||||
summary: Search for items.
|
summary: Search for items.
|
||||||
description: |
|
description: |
|
||||||
Search for items given a search form. The results are grouped
|
Search for items given a search form. The results are grouped
|
||||||
by month by default. For each item, its tags are also
|
by month by default. For each item, its tags and attachments
|
||||||
returned. This uses more queries and is therefore slower, but
|
are also returned. This uses more queries and is therefore
|
||||||
returns all tags to an item.
|
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
|
The `fulltext` field can be used to restrict the results by
|
||||||
using full-text search in the documents contents.
|
using full-text search in the documents contents.
|
||||||
@ -4703,6 +4705,10 @@ components:
|
|||||||
fileCount:
|
fileCount:
|
||||||
type: integer
|
type: integer
|
||||||
format: int32
|
format: int32
|
||||||
|
attachments:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/AttachmentLight"
|
||||||
tags:
|
tags:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
@ -4720,6 +4726,24 @@ components:
|
|||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: "#/components/schemas/HighlightEntry"
|
$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:
|
HighlightEntry:
|
||||||
description: |
|
description: |
|
||||||
Highlighting information for a single field (maybe attachment
|
Highlighting information for a single field (maybe attachment
|
||||||
|
@ -22,6 +22,7 @@ import bitpeace.FileMeta
|
|||||||
import org.http4s.headers.`Content-Type`
|
import org.http4s.headers.`Content-Type`
|
||||||
import org.http4s.multipart.Multipart
|
import org.http4s.multipart.Multipart
|
||||||
import org.log4s.Logger
|
import org.log4s.Logger
|
||||||
|
import docspell.store.queries.QItem
|
||||||
|
|
||||||
trait Conversions {
|
trait Conversions {
|
||||||
|
|
||||||
@ -204,6 +205,7 @@ trait Conversions {
|
|||||||
i.folder.map(mkIdName),
|
i.folder.map(mkIdName),
|
||||||
i.fileCount,
|
i.fileCount,
|
||||||
Nil,
|
Nil,
|
||||||
|
Nil,
|
||||||
i.notes,
|
i.notes,
|
||||||
Nil
|
Nil
|
||||||
)
|
)
|
||||||
@ -215,7 +217,11 @@ trait Conversions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def mkItemLightWithTags(i: OItemSearch.ListItemWithTags): ItemLight =
|
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 = {
|
def mkItemLightWithTags(i: OFulltext.FtsItemWithTags): ItemLight = {
|
||||||
val il = mkItemLightWithTags(i.item)
|
val il = mkItemLightWithTags(i.item)
|
||||||
|
@ -443,7 +443,17 @@ object QItem {
|
|||||||
from.query[ListItem].stream
|
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
|
/** Same as `findItems` but resolves the tags for each item. Note that
|
||||||
* this is implemented by running an additional query per item.
|
* this is implemented by running an additional query per item.
|
||||||
@ -476,8 +486,29 @@ object QItem {
|
|||||||
item <- search
|
item <- search
|
||||||
tagItems <- Stream.eval(RTagItem.findByItem(item.id))
|
tagItems <- Stream.eval(RTagItem.findByItem(item.id))
|
||||||
tags <- Stream.eval(tagItems.traverse(ti => findTag(resolvedTags, ti)))
|
tags <- Stream.eval(tagItems.traverse(ti => findTag(resolvedTags, ti)))
|
||||||
|
attachs <- Stream.eval(findAttachmentLight(item.id))
|
||||||
ftags = tags.flatten.filter(t => t.collective == collective)
|
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] =
|
def delete[F[_]: Sync](store: Store[F])(itemId: Ident, collective: Ident): F[Int] =
|
||||||
|
Loading…
x
Reference in New Issue
Block a user