mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 02:25:30 +00:00
110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package dbmodels
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/pocketbase/dbx"
|
|
"github.com/pocketbase/pocketbase/core"
|
|
)
|
|
|
|
const (
|
|
defaultPlacesSearchLimit = 10
|
|
maxPlacesSearchLimit = 50
|
|
)
|
|
|
|
type PlaceCount struct {
|
|
ID string `db:"id"`
|
|
Count int `db:"count"`
|
|
}
|
|
|
|
// SearchPlaces performs a lightweight search against the places table using the provided term.
|
|
// It matches against the place name and pseudonyms fields.
|
|
func SearchPlaces(app core.App, term string, limit int) ([]*Place, error) {
|
|
places := []*Place{}
|
|
trimmed := strings.TrimSpace(term)
|
|
|
|
if limit <= 0 {
|
|
limit = defaultPlacesSearchLimit
|
|
}
|
|
if limit > maxPlacesSearchLimit {
|
|
limit = maxPlacesSearchLimit
|
|
}
|
|
|
|
query := app.RecordQuery(PLACES_TABLE).
|
|
Limit(int64(limit))
|
|
|
|
if trimmed != "" {
|
|
terms := []string{trimmed}
|
|
if strings.Contains(trimmed, "/") {
|
|
normalized := strings.ReplaceAll(trimmed, "/", " ")
|
|
normalized = strings.Join(strings.Fields(normalized), " ")
|
|
collapsed := strings.ReplaceAll(trimmed, "/", "")
|
|
if normalized != "" && normalized != trimmed {
|
|
terms = append(terms, normalized)
|
|
}
|
|
if collapsed != "" && collapsed != trimmed && collapsed != normalized {
|
|
terms = append(terms, collapsed)
|
|
}
|
|
}
|
|
|
|
conditions := make([]dbx.Expression, 0, len(terms)*2)
|
|
for _, term := range terms {
|
|
conditions = append(conditions,
|
|
dbx.Like(PLACES_NAME_FIELD, term).Match(true, true),
|
|
dbx.Like(PLACES_PSEUDONYMS_FIELD, term).Match(true, true),
|
|
)
|
|
}
|
|
query = query.Where(dbx.Or(conditions...))
|
|
}
|
|
|
|
if err := query.All(&places); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return places, nil
|
|
}
|
|
|
|
// CountPlacesBaende counts the number of Bände (entries) linked to each place.
|
|
// Returns a map of place ID -> count.
|
|
func CountPlacesBaende(app core.App, ids []any) (map[string]int, error) {
|
|
if len(ids) == 0 {
|
|
return map[string]int{}, nil
|
|
}
|
|
|
|
counts := []PlaceCount{}
|
|
|
|
// For each place ID, count how many entries have this place in their places field
|
|
for _, id := range ids {
|
|
var count int64
|
|
|
|
// Query counts entries where the places field contains this place ID
|
|
// PocketBase stores relation fields as JSON arrays, even for single values
|
|
err := app.DB().
|
|
Select("COUNT(*)").
|
|
From(ENTRIES_TABLE).
|
|
Where(dbx.NewExp(
|
|
"json_valid("+PLACES_TABLE+") = 1 AND EXISTS (SELECT 1 FROM json_each("+PLACES_TABLE+") WHERE value = {:id})",
|
|
dbx.Params{"id": id},
|
|
)).
|
|
Row(&count)
|
|
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if count > 0 {
|
|
counts = append(counts, PlaceCount{
|
|
ID: id.(string),
|
|
Count: int(count),
|
|
})
|
|
}
|
|
}
|
|
|
|
ret := make(map[string]int, len(counts))
|
|
for _, c := range counts {
|
|
ret[c.ID] = c.Count
|
|
}
|
|
|
|
return ret, nil
|
|
}
|