mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 09:15:33 +00:00
Lesekabinett & Startseite
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"golang.org/x/text/collate"
|
||||
@@ -12,17 +10,6 @@ import (
|
||||
type AgentsEntries map[string][]*REntriesAgents
|
||||
type AgentsContents map[string][]*RContentsAgents
|
||||
|
||||
func AgentForId(app core.App, id string) (*Agent, error) {
|
||||
agent := &Agent{}
|
||||
err := app.RecordQuery(AGENTS_TABLE).
|
||||
Where(dbx.HashExp{ID_FIELD: id}).
|
||||
One(agent)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return agent, nil
|
||||
}
|
||||
|
||||
func FTS5SearchAgents(app core.App, query string) ([]*Agent, error) {
|
||||
a := []*Agent{}
|
||||
q := NormalizeQuery(query)
|
||||
@@ -216,13 +203,6 @@ func AgentsForLetter(app core.App, letter string) ([]*Agent, error) {
|
||||
return agents, nil
|
||||
}
|
||||
|
||||
func SortAgentsByName(series []*Agent) {
|
||||
collator := collate.New(language.German, collate.Loose)
|
||||
slices.SortFunc(series, func(i, j *Agent) int {
|
||||
return collator.CompareString(i.Name(), j.Name())
|
||||
})
|
||||
}
|
||||
|
||||
func BasicSearchAgents(app core.App, query string) ([]*Agent, []*Agent, error) {
|
||||
agents, err := TitleSearchAgents(app, query)
|
||||
if err != nil {
|
||||
@@ -297,10 +277,11 @@ type AgentCount struct {
|
||||
ID string `db:"id"`
|
||||
}
|
||||
|
||||
func CountAgentsBaende(app core.App) (map[string]int, error) {
|
||||
func CountAgentsBaende(app core.App, ids []any) (map[string]int, error) {
|
||||
couns := []AgentCount{}
|
||||
err := app.RecordQuery(RelationTableName(ENTRIES_TABLE, AGENTS_TABLE)).
|
||||
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
||||
Where(dbx.HashExp{ID_FIELD: ids}).
|
||||
GroupBy(AGENTS_TABLE).
|
||||
All(&couns)
|
||||
|
||||
@@ -316,7 +297,7 @@ func CountAgentsBaende(app core.App) (map[string]int, error) {
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func CountAgentsContents(app core.App) (map[string]int, error) {
|
||||
func CountAgentsContents(app core.App, ids []any) (map[string]int, error) {
|
||||
couns := []AgentCount{}
|
||||
err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)).
|
||||
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
||||
|
||||
@@ -3,16 +3,30 @@ package dbmodels
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// CollectionInfo holds only the ID, a list of single references, and the Recorded flag.
|
||||
// INFO: tries to parse the Sammlungen field of contents.
|
||||
// Doesn't do a good job at all, but it's hard, there are many errors
|
||||
// Safe for concurrent use:
|
||||
var inrex = regexp.MustCompile(`(?is)inr[.:,;]?\s*([\d,\-(?:u.?)\v\f\t –—;\.]+)`)
|
||||
var onrex = regexp.MustCompile(`(?is)obj[.:,;]?\s*([\d,\-(?:u.?)\v\f\t –—;\.]+)`)
|
||||
var dashRegex = regexp.MustCompile(`[–—−‒]`)
|
||||
var delims = regexp.MustCompile(`[;/]+`)
|
||||
var reno = regexp.MustCompile(`\b\d+\b`)
|
||||
|
||||
type CollectionInfo struct {
|
||||
Collection *Content
|
||||
Singles []int
|
||||
Recorded bool
|
||||
Annotation string
|
||||
Collection int
|
||||
Obj []string
|
||||
INr []int
|
||||
Obj_Unsure []string
|
||||
INr_Unsure []int
|
||||
|
||||
ObjRanges []Range[string]
|
||||
INrRanges []Range[int]
|
||||
Recorded bool
|
||||
}
|
||||
|
||||
func (ci CollectionInfo) String() string {
|
||||
@@ -20,107 +34,296 @@ func (ci CollectionInfo) String() string {
|
||||
return string(marshalled)
|
||||
}
|
||||
|
||||
// parseAnnotation detects "nicht erfasst" references (Recorded=false),
|
||||
// then finds all "INr" references (both single values and ranges).
|
||||
// Ranges like "100-105" are fully expanded to singles. Duplicates are removed.
|
||||
// Any references not in `inos` are ignored.
|
||||
func ParseAnnotation(c *Content, annotation string, inos []int) CollectionInfo {
|
||||
func (ci CollectionInfo) ShortString() string {
|
||||
s := strings.Builder{}
|
||||
s.WriteString(strconv.Itoa(ci.Collection))
|
||||
s.WriteString(": ")
|
||||
s.WriteString(ci.Annotation)
|
||||
s.WriteString("\n")
|
||||
|
||||
if ci.Recorded {
|
||||
s.WriteString("recorded")
|
||||
} else {
|
||||
s.WriteString("not recorded")
|
||||
}
|
||||
|
||||
s.WriteString("\n")
|
||||
|
||||
if len(ci.INrRanges) > 0 {
|
||||
s.WriteString("INr-Ranges: ")
|
||||
for _, r := range ci.INrRanges {
|
||||
s.WriteString(strconv.Itoa(r.From))
|
||||
s.WriteString("-")
|
||||
s.WriteString(strconv.Itoa(r.To))
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString("\n")
|
||||
}
|
||||
|
||||
if len(ci.INr) > 0 {
|
||||
s.WriteString("INr-Singles: ")
|
||||
for _, i := range ci.INr {
|
||||
s.WriteString(strconv.Itoa(i))
|
||||
s.WriteString("; ")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ci.INr_Unsure) > 0 {
|
||||
s.WriteString("INr-Unsure: ")
|
||||
if len(ci.INr_Unsure) > 100 {
|
||||
s.WriteString("many")
|
||||
} else {
|
||||
for _, i := range ci.INr_Unsure {
|
||||
s.WriteString(strconv.Itoa(i))
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString("\n")
|
||||
}
|
||||
}
|
||||
|
||||
if len(ci.ObjRanges) > 0 {
|
||||
s.WriteString("Obj-Ranges: ")
|
||||
for _, r := range ci.ObjRanges {
|
||||
s.WriteString(r.From)
|
||||
s.WriteString("-")
|
||||
s.WriteString(r.To)
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString("\n")
|
||||
}
|
||||
|
||||
if len(ci.Obj) > 0 {
|
||||
s.WriteString("Obj-Singles: ")
|
||||
for _, i := range ci.Obj {
|
||||
s.WriteString(i)
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString("\n")
|
||||
}
|
||||
|
||||
if len(ci.Obj_Unsure) > 0 {
|
||||
s.WriteString("Obj-Unsure: ")
|
||||
for _, i := range ci.Obj_Unsure {
|
||||
s.WriteString(i)
|
||||
s.WriteString("; ")
|
||||
}
|
||||
s.WriteString("\n")
|
||||
}
|
||||
|
||||
return s.String()
|
||||
}
|
||||
|
||||
type Range[T any] struct {
|
||||
From T
|
||||
To T
|
||||
}
|
||||
|
||||
func ParseAnnotation(c int, annotation string, inos []int, objnos []string) CollectionInfo {
|
||||
ci := CollectionInfo{
|
||||
Annotation: annotation,
|
||||
Collection: c,
|
||||
Singles: []int{},
|
||||
Recorded: true, // Default
|
||||
Recorded: true,
|
||||
}
|
||||
|
||||
// 1) Detect phrases like "nicht erfasst", "nicht aufgenommen", etc.
|
||||
notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"}
|
||||
lowerAnn := strings.ToLower(annotation)
|
||||
if strings.Contains(lowerAnn, "nicht") {
|
||||
for _, kw := range notRecordedPatterns {
|
||||
if strings.Contains(lowerAnn, kw) {
|
||||
ci.Recorded = false
|
||||
break
|
||||
split := strings.Split(annotation, "/)")
|
||||
|
||||
inomap := make(map[int]bool)
|
||||
for _, i := range inos {
|
||||
inomap[i] = true
|
||||
}
|
||||
|
||||
objnomap := make(map[string]bool)
|
||||
for _, o := range objnos {
|
||||
objnomap[o] = true
|
||||
}
|
||||
|
||||
unsure_inr := func(in int) {
|
||||
instr := strconv.Itoa(in)
|
||||
if _, ok := objnomap[instr]; ok {
|
||||
ci.Obj = append(ci.Obj, instr)
|
||||
} else {
|
||||
ci.INr_Unsure = append(ci.INr_Unsure, in)
|
||||
}
|
||||
}
|
||||
|
||||
unsure_inr_range := func(r Range[int]) {
|
||||
cfrom := strconv.Itoa(r.From)
|
||||
cto := strconv.Itoa(r.To)
|
||||
_, ok := objnomap[cfrom]
|
||||
_, ok2 := objnomap[cto]
|
||||
if ok && ok2 {
|
||||
ci.ObjRanges = append(ci.ObjRanges, Range[string]{From: cfrom, To: cto})
|
||||
} else {
|
||||
for i := r.From; i <= r.To; i++ {
|
||||
unsure_inr(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We'll keep singles in a map for deduplication
|
||||
singlesMap := make(map[int]struct{})
|
||||
for _, s := range split {
|
||||
l := strings.ToLower(s)
|
||||
|
||||
// 2) Regex that matches "INr" plus the numeric portion (including dash / punctuation).
|
||||
re := regexp.MustCompile(`(?i)\bINr[.:]?\s+([\d,\-\s–—;/.]+)`)
|
||||
matches := re.FindAllStringSubmatch(annotation, -1)
|
||||
|
||||
// Regex to unify different dash characters into a simple '-'
|
||||
dashRegex := regexp.MustCompile(`[–—−‒]`)
|
||||
|
||||
// Helper to expand a range, e.g. 10615–10621 => 10615..10621
|
||||
expandRange := func(fromVal, toVal int) {
|
||||
// If reversed, its a typo
|
||||
if fromVal > toVal {
|
||||
return
|
||||
}
|
||||
for v := fromVal; v <= toVal; v++ {
|
||||
if inList(v, inos) {
|
||||
singlesMap[v] = struct{}{}
|
||||
// TODO: before this, we may cut the annotation into /) pieces
|
||||
notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"}
|
||||
if strings.Contains(l, "nicht") {
|
||||
for _, kw := range notRecordedPatterns {
|
||||
if strings.Contains(l, kw) {
|
||||
ci.Recorded = false
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matches := inrex.FindAllStringSubmatch(s, -1)
|
||||
inRanges, inSingles := findINrRangesSingles(matches)
|
||||
|
||||
// INFO: Heuristics
|
||||
for _, in := range inSingles {
|
||||
if _, ok := inomap[in]; ok {
|
||||
ci.INr = append(ci.INr, in)
|
||||
} else {
|
||||
unsure_inr(in)
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range inRanges {
|
||||
if r.From < r.To {
|
||||
_, ok := inomap[r.From]
|
||||
_, ok2 := inomap[r.To]
|
||||
if ok && ok2 {
|
||||
ci.INrRanges = append(ci.INrRanges, r)
|
||||
continue
|
||||
}
|
||||
|
||||
unsure_inr_range(r)
|
||||
} else {
|
||||
for i := r.From; i <= r.To; i++ {
|
||||
ci.INr_Unsure = append(ci.INr_Unsure, i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
matches = onrex.FindAllStringSubmatch(s, -1)
|
||||
objRanges, objSingles := findONrRangesSingles(matches)
|
||||
|
||||
for _, o := range objSingles {
|
||||
if _, ok := objnomap[o]; ok {
|
||||
ci.Obj = append(ci.Obj, o)
|
||||
} else {
|
||||
ci.Obj_Unsure = append(ci.Obj_Unsure, o)
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range objRanges {
|
||||
if r.From < r.To {
|
||||
_, ok := objnomap[r.From]
|
||||
_, ok2 := objnomap[r.To]
|
||||
if ok && ok2 {
|
||||
ci.ObjRanges = append(ci.ObjRanges, r)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for _, m := range matches {
|
||||
numericChunk := m[1]
|
||||
return ci
|
||||
}
|
||||
|
||||
// Replace typographic dashes with ASCII hyphen
|
||||
numericChunk = dashRegex.ReplaceAllString(numericChunk, "-")
|
||||
func findINrRangesSingles(matches [][]string) ([]Range[int], []int) {
|
||||
ranges := make([]Range[int], 0)
|
||||
singles := make([]int, 0)
|
||||
|
||||
// Also unify semicolons or slashes to commas
|
||||
extraDelims := regexp.MustCompile(`[;/]+`)
|
||||
numericChunk = extraDelims.ReplaceAllString(numericChunk, ",")
|
||||
|
||||
// Now split on commas
|
||||
parts := strings.Split(numericChunk, ",")
|
||||
for _, match := range matches {
|
||||
chunk := match[1]
|
||||
normalized := dashRegex.ReplaceAllString(chunk, "-")
|
||||
// WARNING: Replacing the OBj and INr delimiter ; with a comma here.
|
||||
// It's a problem if the Obj was left out: INr 323345-323398; 23-53
|
||||
// Here is an Obj often, but not always ^
|
||||
// We do some heuristics later on to differentiate INr from Obj.
|
||||
normalized = delims.ReplaceAllString(normalized, ",")
|
||||
parts := strings.Split(normalized, ",")
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
// If we see a hyphen, treat it as a range
|
||||
if strings.Contains(p, "-") {
|
||||
rangeParts := strings.SplitN(p, "-", 2)
|
||||
if len(rangeParts) == 2 {
|
||||
fromStr := strings.TrimSpace(rangeParts[0])
|
||||
toStr := strings.TrimSpace(rangeParts[1])
|
||||
if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil {
|
||||
if toVal, errTo := strconv.Atoi(toStr); errTo == nil {
|
||||
expandRange(fromVal, toVal)
|
||||
|
||||
rangeParts := strings.Split(p, "-")
|
||||
if len(rangeParts) == 2 {
|
||||
// INFO: we have a range, most prob
|
||||
fromStr := strings.TrimSpace(rangeParts[0])
|
||||
toStr := strings.TrimSpace(rangeParts[1])
|
||||
if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil {
|
||||
if toVal, errTo := strconv.Atoi(toStr); errTo == nil {
|
||||
ranges = append(ranges, Range[int]{From: fromVal, To: toVal})
|
||||
continue
|
||||
}
|
||||
to := reno.FindAllString(toStr, -1)
|
||||
if len(to) >= 1 {
|
||||
if val, err := strconv.Atoi(to[0]); err == nil {
|
||||
ranges = append(ranges, Range[int]{From: fromVal, To: val})
|
||||
}
|
||||
if len(to) > 1 {
|
||||
if val, err := strconv.Atoi(to[1]); err == nil {
|
||||
singles = append(singles, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Single integer reference
|
||||
if val, err := strconv.Atoi(p); err == nil {
|
||||
if inList(val, inos) {
|
||||
singlesMap[val] = struct{}{}
|
||||
continue
|
||||
}
|
||||
|
||||
rangeParts = strings.Split(p, " u")
|
||||
for _, r := range rangeParts {
|
||||
trimmed := strings.TrimSpace(r)
|
||||
matches := reno.FindAllString(trimmed, -1)
|
||||
for _, m := range matches {
|
||||
if val, err := strconv.Atoi(m); err == nil {
|
||||
singles = append(singles, val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Flatten the map into a sorted slice
|
||||
for s := range singlesMap {
|
||||
ci.Singles = append(ci.Singles, s)
|
||||
}
|
||||
sort.Ints(ci.Singles)
|
||||
|
||||
return ci
|
||||
return ranges, singles
|
||||
}
|
||||
|
||||
// inList checks membership in `inos`
|
||||
func inList(x int, list []int) bool {
|
||||
for _, item := range list {
|
||||
if item == x {
|
||||
return true
|
||||
func findONrRangesSingles(matches [][]string) ([]Range[string], []string) {
|
||||
ranges := make([]Range[string], 0)
|
||||
singles := make([]string, 0)
|
||||
|
||||
for _, match := range matches {
|
||||
chunk := match[1]
|
||||
normalized := dashRegex.ReplaceAllString(chunk, "-")
|
||||
normalized = delims.ReplaceAllString(normalized, ",")
|
||||
parts := strings.Split(normalized, ",")
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
rangeParts := strings.Split(p, "-")
|
||||
if len(rangeParts) == 2 {
|
||||
// INFO: we have a range, most prob
|
||||
fromStr := strings.TrimSpace(rangeParts[0])
|
||||
toStr := strings.TrimSpace(rangeParts[1])
|
||||
ranges = append(ranges, Range[string]{From: fromStr, To: toStr})
|
||||
continue
|
||||
}
|
||||
|
||||
rangeParts = strings.Split(p, " u")
|
||||
for _, r := range rangeParts {
|
||||
trimmed := strings.TrimSpace(r)
|
||||
matches := reno.FindAllString(trimmed, -1)
|
||||
for _, m := range matches {
|
||||
singles = append(singles, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
||||
return ranges, singles
|
||||
}
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
package dbmodels
|
||||
|
||||
type FieldMetaData struct {
|
||||
MetaData MetaData `json:",omitempty" db:"edit_fielddata"`
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
|
||||
type ContentsAgents map[string][]*RContentsAgents
|
||||
|
||||
func ContentsForEntry(app core.App, entry *Entry) ([]*Content, error) {
|
||||
contents := []*Content{}
|
||||
err := app.RecordQuery(CONTENTS_TABLE).
|
||||
Where(dbx.HashExp{ENTRIES_TABLE: entry.Id}).
|
||||
All(&contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
slices.SortFunc(contents, func(i, j *Content) int {
|
||||
r := i.Numbering() - j.Numbering()
|
||||
if r == 0 {
|
||||
return 0
|
||||
}
|
||||
if r < 0 {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})
|
||||
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func ContentsForAgent(app core.App, agentId string) ([]*Content, error) {
|
||||
relations := []*RContentsAgents{}
|
||||
err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)).
|
||||
Where(dbx.HashExp{AGENTS_TABLE: agentId}).
|
||||
All(&relations)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cids := []any{}
|
||||
for _, r := range relations {
|
||||
cids = append(cids, r.Content())
|
||||
}
|
||||
|
||||
contents := []*Content{}
|
||||
err = app.RecordQuery(CONTENTS_TABLE).
|
||||
Where(dbx.HashExp{ID_FIELD: cids}).
|
||||
All(&contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
func SortContentsByEntryNumbering(contents []*Content, entries map[string]*Entry) {
|
||||
slices.SortFunc(contents, func(i, j *Content) int {
|
||||
ii, iok := entries[i.Entry()]
|
||||
ij, jok := entries[j.Entry()]
|
||||
if iok && jok {
|
||||
ret := ii.Year() - ij.Year()
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
|
||||
ret = strings.Compare(ii.PreferredTitle(), ij.PreferredTitle())
|
||||
if ret != 0 {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
||||
r := i.Numbering() - j.Numbering()
|
||||
if r == 0 {
|
||||
return 0
|
||||
}
|
||||
if r < 0 {
|
||||
return -1
|
||||
}
|
||||
return 1
|
||||
})
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"golang.org/x/text/collate"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func AllPlaces(app core.App) ([]*Place, error) {
|
||||
places := []*Place{}
|
||||
err := app.RecordQuery(PLACES_TABLE).
|
||||
OrderBy(PLACES_NAME_FIELD).
|
||||
All(&places)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return places, nil
|
||||
}
|
||||
|
||||
func SortPlacesByName(places []*Place) {
|
||||
collator := collate.New(language.German)
|
||||
slices.SortFunc(places, func(i, j *Place) int {
|
||||
return collator.CompareString(i.Name(), j.Name())
|
||||
})
|
||||
}
|
||||
|
||||
func PlaceForId(app core.App, id string) (*Place, error) {
|
||||
place := &Place{}
|
||||
err := app.RecordQuery(PLACES_TABLE).
|
||||
Where(dbx.HashExp{ID_FIELD: id}).
|
||||
One(place)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return place, nil
|
||||
}
|
||||
|
||||
func PlacesForEntry(app core.App, entry *Entry) (map[string]*Place, error) {
|
||||
ids := []any{}
|
||||
places := map[string]*Place{}
|
||||
|
||||
for _, r := range entry.Places() {
|
||||
ids = append(ids, r)
|
||||
}
|
||||
if len(ids) == 0 {
|
||||
return places, nil
|
||||
}
|
||||
|
||||
p := []*Place{}
|
||||
err := app.RecordQuery(PLACES_TABLE).
|
||||
Where(dbx.HashExp{ID_FIELD: ids}).
|
||||
All(&p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, place := range p {
|
||||
places[place.Id] = place
|
||||
}
|
||||
|
||||
return places, nil
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
// - any id or multiple IDs (of an indexed field)
|
||||
// 3. Naming convention: <TableName>_<FilteredField>[s]
|
||||
// For scanning, with an Iter_ prefix, yields single row results
|
||||
// TODO: It would be nice if the return types of these, if arrays were custom types that implemented
|
||||
// some often uses functions, like getting all IDs, or creating a map of the IDs.
|
||||
|
||||
func REntriesAgents_Agent(app core.App, id string) ([]*REntriesAgents, error) {
|
||||
return TableByFields[*REntriesAgents](
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"iter"
|
||||
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
)
|
||||
import ()
|
||||
|
||||
// INFO: Iterator queries to be reused
|
||||
// Rules
|
||||
@@ -15,23 +11,24 @@ import (
|
||||
// 3. Naming convention: Iter_<TableName>_<FilteredField>[s]
|
||||
|
||||
// BUG: this is not working as expected, see Iter_TableByField in queryhelpers.go
|
||||
func Iter_REntriesAgents_Agent(app core.App, id string) (iter.Seq2[*REntriesAgents, error], error) {
|
||||
innerIterator, err := Iter_TableByField[REntriesAgents](
|
||||
app,
|
||||
RelationTableName(ENTRIES_TABLE, AGENTS_TABLE),
|
||||
AGENTS_TABLE,
|
||||
id,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(yield func(*REntriesAgents, error) bool) {
|
||||
for item, err := range innerIterator {
|
||||
if !yield(item, err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
// func Iter_REntriesAgents_Agent(app core.App, id string) (iter.Seq2[*REntriesAgents, error], error) {
|
||||
// innerIterator, err := Iter_TableByField[REntriesAgents](
|
||||
// app,
|
||||
// RelationTableName(ENTRIES_TABLE, AGENTS_TABLE),
|
||||
// AGENTS_TABLE,
|
||||
// id,
|
||||
// )
|
||||
//
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return func(yield func(*REntriesAgents, error) bool) {
|
||||
// for item, err := range innerIterator {
|
||||
// if !yield(item, err) {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package dbmodels
|
||||
|
||||
import (
|
||||
"iter"
|
||||
"reflect"
|
||||
|
||||
"github.com/pocketbase/dbx"
|
||||
@@ -10,100 +9,50 @@ import (
|
||||
|
||||
// INFO: These functions are very abstract interfaces to the DB that help w querying
|
||||
|
||||
// BUG: this is not working:
|
||||
// github.com/pocketbase/pocketbase/apis.NewRouter.panicRecover.func3.1()
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/apis/middlewares.go:269 +0x13c
|
||||
//
|
||||
// panic({0x15b34c0?, 0x2831680?})
|
||||
//
|
||||
// /usr/local/go/src/runtime/panic.go:787 +0x132
|
||||
//
|
||||
// github.com/pocketbase/pocketbase/core.(*Record).FieldsData(0xc000632820)
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/core/record_model.go:774 +0x1a
|
||||
//
|
||||
// github.com/pocketbase/pocketbase/core.(*Record).PostScan(0xc000632820)
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/core/record_model.go:591 +0x4e
|
||||
//
|
||||
// github.com/pocketbase/dbx.(*Rows).ScanStruct(0xc00052e6d0, {0x175f840?, 0xc000586060?})
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/dbx@v1.11.0/rows.go:97 +0x32e
|
||||
//
|
||||
// github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels.Iter_TableByField[...].func1()
|
||||
//
|
||||
// /home/simon/source/musenalm/dbmodels/queryhelpers.go:23 +0x65
|
||||
//
|
||||
// github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels.Iter_REntriesAgents_Agent.func1(0xc000624840)
|
||||
//
|
||||
// /home/simon/source/musenalm/dbmodels/queries_iter.go:30 +0xae
|
||||
//
|
||||
// github.com/Theodor-Springmann-Stiftung/musenalm/pages.(*PersonResult).FilterEntriesByPerson(0x1762c40?, {0x1dfba88, 0xc000438870}, {0xc00004627c, 0xf}, 0xc000064720)
|
||||
//
|
||||
// /home/simon/source/musenalm/pages/person.go:111 +0x248
|
||||
//
|
||||
// github.com/Theodor-Springmann-Stiftung/musenalm/pages.NewPersonResult({0x1dfba88, 0xc000438870}, {0xc00004627c, 0xf})
|
||||
//
|
||||
// /home/simon/source/musenalm/pages/person.go:92 +0x4f
|
||||
//
|
||||
// github.com/Theodor-Springmann-Stiftung/musenalm/pages.(*PersonPage).Setup.func1(0xc0002da000)
|
||||
//
|
||||
// /home/simon/source/musenalm/pages/person.go:46 +0x1ee
|
||||
//
|
||||
// github.com/pocketbase/pocketbase/tools/hook.(*Hook[...]).Trigger.func1()
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/tools/hook/hook.go:169 +0x5d
|
||||
//
|
||||
// github.com/pocketbase/pocketbase/tools/hook.(*Event).Next(0xc0002da000?)
|
||||
//
|
||||
// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/tools/hook/event.go:32 +0x17
|
||||
//
|
||||
// github.com/pocketbase/pocketbase/apis.NewRouter.BodyLimit.func7(0xc0002da000)
|
||||
//
|
||||
// /home
|
||||
|
||||
const (
|
||||
QUERY_PARTITION_SIZE = 1200
|
||||
)
|
||||
|
||||
func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) {
|
||||
rows, err := app.RecordQuery(table).
|
||||
Where(dbx.HashExp{field: value}).
|
||||
Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(yield func(*T, error) bool) {
|
||||
for rows.Next() {
|
||||
var item T
|
||||
err := rows.ScanStruct(&item)
|
||||
if !yield(&item, err) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) {
|
||||
rows, err := app.RecordQuery(table).
|
||||
Where(dbx.HashExp{ID_FIELD: id}).
|
||||
Rows()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return func(yield func(*T, error) bool) {
|
||||
for rows.Next() {
|
||||
var item T
|
||||
rows.Scan(&item)
|
||||
if !yield(&item, nil) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
// BUG: this is not working, throws an exception
|
||||
// github.com/pocketbase/pocketbase/apis.NewRouter.panicRecover.func3.1()
|
||||
//
|
||||
// func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) {
|
||||
// rows, err := app.RecordQuery(table).
|
||||
// Where(dbx.HashExp{field: value}).
|
||||
// Rows()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return func(yield func(*T, error) bool) {
|
||||
// for rows.Next() {
|
||||
// var item T
|
||||
// err := rows.ScanStruct(&item)
|
||||
// if !yield(&item, err) {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }, nil
|
||||
// }
|
||||
//
|
||||
// func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) {
|
||||
// rows, err := app.RecordQuery(table).
|
||||
// Where(dbx.HashExp{ID_FIELD: id}).
|
||||
// Rows()
|
||||
// if err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
//
|
||||
// return func(yield func(*T, error) bool) {
|
||||
// for rows.Next() {
|
||||
// var item T
|
||||
// rows.Scan(&item)
|
||||
// if !yield(&item, nil) {
|
||||
// return
|
||||
// }
|
||||
// }
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
func TableByField[T interface{}](app core.App, table, field string, value string) (T, error) {
|
||||
var ret T
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// INFO: Functions that implement sorting of which sqlite is not capable of.
|
||||
|
||||
func Sort_Series_Title(series []*Series) {
|
||||
collator := collate.New(language.German)
|
||||
slices.SortFunc(series, func(i, j *Series) int {
|
||||
@@ -55,3 +57,10 @@ func Sort_Contents_Numbering(contents []*Content) {
|
||||
return datatypes.CompareFloat(i.Numbering(), j.Numbering())
|
||||
})
|
||||
}
|
||||
|
||||
func Sort_Places_Name(places []*Place) {
|
||||
collator := collate.New(language.German)
|
||||
slices.SortFunc(places, func(i, j *Place) int {
|
||||
return collator.CompareString(i.Name(), j.Name())
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user