Files
musenalm/dbmodels/places_functions.go
2026-01-14 21:40:48 +01:00

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
}