mirror of
https://github.com/TheAnachronism/docspell.git
synced 2025-06-22 02:18:26 +00:00
Correctly count tag categories
If multiple tags of the same category are applied to the same item, just summing tag counts will produce the wrong results as now items are counted multiple times.
This commit is contained in:
@ -9,11 +9,11 @@ object DBFunction {
|
||||
val countAll: DBFunction = CountAll
|
||||
|
||||
def countAs[A](column: Column[A]): DBFunction =
|
||||
Count(column)
|
||||
Count(column, false)
|
||||
|
||||
case object CountAll extends DBFunction
|
||||
|
||||
case class Count(column: Column[_]) extends DBFunction
|
||||
case class Count(column: Column[_], distinct: Boolean) extends DBFunction
|
||||
|
||||
case class Max(expr: SelectExpr) extends DBFunction
|
||||
|
||||
|
@ -63,7 +63,10 @@ trait DSL extends DoobieMeta {
|
||||
FromExpr.From(sel, alias)
|
||||
|
||||
def count(c: Column[_]): DBFunction =
|
||||
DBFunction.Count(c)
|
||||
DBFunction.Count(c, false)
|
||||
|
||||
def countDistinct(c: Column[_]): DBFunction =
|
||||
DBFunction.Count(c, true)
|
||||
|
||||
def countAll: DBFunction =
|
||||
DBFunction.CountAll
|
||||
|
@ -13,8 +13,9 @@ object DBFunctionBuilder extends CommonBuilder {
|
||||
case DBFunction.CountAll =>
|
||||
sql"COUNT(*)"
|
||||
|
||||
case DBFunction.Count(col) =>
|
||||
sql"COUNT(" ++ column(col) ++ fr")"
|
||||
case DBFunction.Count(col, distinct) =>
|
||||
if (distinct) sql"COUNT(DISTINCT " ++ column(col) ++ fr")"
|
||||
else sql"COUNT(" ++ column(col) ++ fr")"
|
||||
|
||||
case DBFunction.Max(expr) =>
|
||||
sql"MAX(" ++ SelectExprBuilder.build(expr) ++ fr")"
|
||||
|
@ -0,0 +1,3 @@
|
||||
package docspell.store.queries
|
||||
|
||||
final case class CategoryCount(category: String, count: Int)
|
@ -190,9 +190,38 @@ object QItem {
|
||||
for {
|
||||
count <- searchCountSummary(today)(q)
|
||||
tags <- searchTagSummary(today)(q)
|
||||
cats <- searchTagCategorySummary(today)(q)
|
||||
fields <- searchFieldSummary(today)(q)
|
||||
folders <- searchFolderSummary(today)(q)
|
||||
} yield SearchSummary(count, tags, fields, folders)
|
||||
} yield SearchSummary(count, tags, cats, fields, folders)
|
||||
|
||||
def searchTagCategorySummary(
|
||||
today: LocalDate
|
||||
)(q: Query): ConnectionIO[List[CategoryCount]] = {
|
||||
val tagFrom =
|
||||
from(ti)
|
||||
.innerJoin(tag, tag.tid === ti.tagId)
|
||||
.innerJoin(i, i.id === ti.itemId)
|
||||
|
||||
val tagCloud =
|
||||
findItemsBase(q.fix, today, 0).unwrap
|
||||
.withSelect(select(tag.category).append(countDistinct(i.id).as("num")))
|
||||
.changeFrom(_.prepend(tagFrom))
|
||||
.changeWhere(c => c && queryCondition(today, q.fix.account.collective, q.cond))
|
||||
.groupBy(tag.category)
|
||||
.build
|
||||
.query[CategoryCount]
|
||||
.to[List]
|
||||
|
||||
// the previous query starts from tags, so items with tag-count=0
|
||||
// are not included they are fetched separately
|
||||
for {
|
||||
existing <- tagCloud
|
||||
allCats <- RTag.listCategories(q.fix.account.collective)
|
||||
other = allCats.diff(existing.map(_.category))
|
||||
} yield existing ++ other.map(CategoryCount(_, 0))
|
||||
|
||||
}
|
||||
|
||||
def searchTagSummary(today: LocalDate)(q: Query): ConnectionIO[List[TagCount]] = {
|
||||
val tagFrom =
|
||||
|
@ -3,6 +3,7 @@ package docspell.store.queries
|
||||
case class SearchSummary(
|
||||
count: Int,
|
||||
tags: List[TagCount],
|
||||
cats: List[CategoryCount],
|
||||
fields: List[FieldStats],
|
||||
folders: List[FolderCount]
|
||||
)
|
||||
|
@ -2,4 +2,4 @@ package docspell.store.queries
|
||||
|
||||
import docspell.store.records.RTag
|
||||
|
||||
case class TagCount(tag: RTag, count: Int)
|
||||
final case class TagCount(tag: RTag, count: Int)
|
||||
|
Reference in New Issue
Block a user