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:
Eike Kettner
2021-04-11 13:57:49 +02:00
parent 132730b19c
commit 3e0914ece7
10 changed files with 79 additions and 8 deletions

View File

@ -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

View File

@ -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

View File

@ -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")"

View File

@ -0,0 +1,3 @@
package docspell.store.queries
final case class CategoryCount(category: String, count: Int)

View File

@ -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 =

View File

@ -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]
)

View File

@ -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)