Abschluss Bandsuche

This commit is contained in:
Simon Martens
2025-02-27 13:02:23 +01:00
parent 57f95122c8
commit d2e7f91c92
11 changed files with 330 additions and 195 deletions

View File

@@ -26,14 +26,13 @@ func AgentForId(app core.App, id string) (*Agent, error) {
func FTS5SearchAgents(app core.App, query string) ([]*Agent, error) {
a := []*Agent{}
q := NormalizeQuery(query)
if len(q) == 0 {
req := IntoQueryRequests([]string{AGENTS_NAME_FIELD, AGENTS_PSEUDONYMS_FIELD, REFERENCES_FIELD, AGENTS_BIOGRAPHICAL_DATA_FIELD, ANNOTATION_FIELD}, q)
if len(req) == 0 {
return a, nil
}
ids, err := FTS5Search(app, AGENTS_TABLE, FTS5QueryRequest{
Fields: []string{AGENTS_NAME_FIELD, AGENTS_PSEUDONYMS_FIELD, REFERENCES_FIELD, AGENTS_BIOGRAPHICAL_DATA_FIELD, ANNOTATION_FIELD},
Query: q,
})
ids, err := FTS5Search(app, AGENTS_TABLE, req...)
if err != nil {
return nil, err

View File

@@ -2,8 +2,10 @@ package dbmodels
import (
"errors"
"fmt"
"strconv"
"strings"
"unicode"
"github.com/Theodor-Springmann-Stiftung/musenalm/helpers/datatypes"
"github.com/pocketbase/dbx"
@@ -99,22 +101,125 @@ var CONTENTS_FTS5_FIELDS = []string{
var ErrInvalidQuery = errors.New("invalid input into the search function")
func NormalizeQuery(query string) []string {
query = datatypes.NormalizeString(query)
query = datatypes.DeleteTags(query)
query = datatypes.RemovePunctuation(query)
query = cases.Lower(language.German).String(query)
// TODO: how to normalize, which unicode normalization to use?
type Query struct {
Include []string // Phrases that should be matched
Exclude []string // Phrases that should not be matched
UnsafeI []string // Phrases < 3 characters
UnsafeE []string // Phrases < 3 characters excluded
}
split := strings.Split(query, " ")
res := []string{}
for _, s := range split {
if len(s) > 2 {
res = append(res, s)
// Parses query strings like
// word another "this is a phrase" -notthis aword -alsonotthis -"also not this"
// into seperate phrases
func NormalizeQuery(query string) Query {
query = datatypes.NormalizeString(query)
// TODO: how to normalize, which unicode normalization to use?
// query = datatypes.RemovePunctuation(query)
query = cases.Lower(language.German).String(query)
var include []string
var exclude []string
var unsafeI []string
var unsafeE []string
isInQuotes := false
isExcluded := false
var cToken strings.Builder
at := func() {
if cToken.Len() == 0 {
return
}
t := cToken.String()
if len(t) < 3 && isExcluded {
unsafeE = append(unsafeE, t)
return
} else if len(t) < 3 {
unsafeI = append(unsafeI, t)
return
}
if len(t) >= 3 && isExcluded {
exclude = append(exclude, t)
return
} else if len(t) >= 3 {
include = append(include, t)
return
}
}
return res
reset := func() {
isInQuotes = false
isExcluded = false
cToken.Reset()
}
addToken := func() {
at()
reset()
}
for _, r := range query {
fmt.Printf("Rune: %v\n", r)
if r == '"' {
if isInQuotes {
addToken()
} else if cToken.Len() == 0 {
isInQuotes = true
}
// INFO: - is punctuation, so the order of cases is important
} else if r == 45 && cToken.Len() == 0 {
isExcluded = true
} else if unicode.IsSpace(r) && !isInQuotes {
addToken()
} else if unicode.IsPunct(r) && !isInQuotes {
addToken()
} else {
cToken.WriteRune(r)
}
}
if cToken.Len() > 0 {
at()
}
fmt.Printf("Query: %v\n", query)
fmt.Printf("Include: %v\n", include)
fmt.Printf("Exclude: %v\n", exclude)
fmt.Printf("UnsafeI: %v\n", unsafeI)
fmt.Printf("UnsafeE: %v\n", unsafeE)
return Query{
Include: include,
Exclude: exclude,
UnsafeI: unsafeI,
UnsafeE: unsafeE,
}
}
// INFO: Takes in fields and a Query object
func IntoQueryRequests(f []string, q Query) []FTS5QueryRequest {
ret := []FTS5QueryRequest{}
if len(q.Include) > 0 {
ret = append(ret, FTS5QueryRequest{
Fields: f,
Query: q.Include,
OP: OP_AND,
})
}
if len(q.Exclude) > 0 {
ret = append(ret, FTS5QueryRequest{
Fields: f,
Query: q.Exclude,
OP: OP_NOT,
})
}
return ret
}
func FTS5Search(app core.App, table string, mapfq ...FTS5QueryRequest) ([]*FTS5IDQueryResult, error) {
@@ -125,7 +230,16 @@ func FTS5Search(app core.App, table string, mapfq ...FTS5QueryRequest) ([]*FTS5I
q := NewFTS5Query().From(table).SelectID()
for _, v := range mapfq {
for _, que := range v.Query {
q.AndMatch(v.Fields, que)
switch v.OP {
case OP_AND:
q.AndMatch(v.Fields, que)
case OP_OR:
q.OrMatch(v.Fields, que)
case OP_NOT:
q.NotMatch(v.Fields, que)
case NONE:
q.AndMatch(v.Fields, que)
}
}
}

View File

@@ -9,6 +9,7 @@ import (
type FTS5QueryRequest struct {
Fields []string
Query []string
OP Operator
}
type FTS5IDQueryResult struct {

View File

@@ -112,6 +112,11 @@ func Series_IDs(app core.App, ids []any) ([]*Series, error) {
return TableByIDs[[]*Series](app, SERIES_TABLE, ids)
}
func Series_MusenalmID(app core.App, id string) (*Series, error) {
ret, err := TableByField[Series](app, SERIES_TABLE, MUSENALMID_FIELD, id)
return &ret, err
}
func Series_ID(app core.App, id string) (*Series, error) {
ret, err := TableByID[Series](app, SERIES_TABLE, id)
return &ret, err

View File

@@ -43,14 +43,13 @@ func BasicSearchSeries(app core.App, query string) ([]*Series, []*Series, error)
// INFO: Needing to differentiate matches
querysplit := NormalizeQuery(query)
if len(querysplit) == 0 {
req := IntoQueryRequests([]string{SERIES_TITLE_FIELD, ANNOTATION_FIELD, REFERENCES_FIELD}, querysplit)
if len(req) == 0 {
return series, []*Series{}, nil
}
altids, err := FTS5Search(app, SERIES_TABLE, FTS5QueryRequest{
Fields: []string{SERIES_TITLE_FIELD, ANNOTATION_FIELD, REFERENCES_FIELD},
Query: querysplit,
})
altids, err := FTS5Search(app, SERIES_TABLE, req...)
if err != nil {
return nil, nil, err
}