Add persistent multi-tag include and exclude filters

This commit is contained in:
Lars Nolden
2026-09-19 12:44:05 +02:00
parent 8aab21fe9e
commit 9cc3130b4f
11 changed files with 409 additions and 46 deletions
+18 -20
View File
@@ -15,13 +15,14 @@ import (
type Store struct{ db *sql.DB }
type Filter struct {
From string `json:"from"`
To string `json:"to"`
Currency string `json:"currency"`
AccountID string `json:"account_id"`
CategoryID string `json:"category_id"`
TagID string `json:"tag_id"`
MerchantID string `json:"merchant_id"`
From string `json:"from"`
To string `json:"to"`
Currency string `json:"currency"`
AccountID string `json:"account_id"`
CategoryID string `json:"category_id"`
TagIDs []string `json:"tag_ids"`
ExcludeTagIDs []string `json:"exclude_tag_ids"`
MerchantID string `json:"merchant_id"`
}
type Total struct {
@@ -272,21 +273,18 @@ func (f Filter) where() (string, []any) {
add("t.account_id = ?", f.AccountID)
add("t.merchant_id = ?", f.MerchantID)
add("EXISTS (SELECT 1 FROM category_ancestors ca WHERE ca.category_id = t.category_id AND ca.ancestor_id = ?)", f.CategoryID)
if f.TagID != "" {
ids := strings.Split(f.TagID, ",")
placeholders := make([]string, 0, len(ids))
for _, id := range ids {
id = strings.TrimSpace(id)
if id != "" {
placeholders = append(placeholders, "?")
args = append(args, id)
}
addTags := func(predicate string, ids []string) {
if len(ids) == 0 {
return
}
if len(placeholders) == 0 {
clauses = append(clauses, "FALSE")
} else {
clauses = append(clauses, "EXISTS (SELECT 1 FROM transaction_tags tt WHERE tt.transaction_id = t.id AND tt.tag_id IN ("+strings.Join(placeholders, ",")+"))")
placeholders := make([]string, len(ids))
for i, id := range ids {
placeholders[i] = "?"
args = append(args, id)
}
clauses = append(clauses, predicate+" (SELECT 1 FROM transaction_tags tt WHERE tt.transaction_id = t.id AND tt.tag_id IN ("+strings.Join(placeholders, ",")+"))")
}
addTags("EXISTS", f.TagIDs)
addTags("NOT EXISTS", f.ExcludeTagIDs)
return strings.Join(clauses, " AND "), args
}