From 9ca2ebb75f7772e2281e8b43782f725ad5fc3672 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Fri, 3 Jan 2025 18:57:22 +0100 Subject: [PATCH] Finalized resolver --- providers/xmlprovider/models.go | 29 ++++++++ providers/xmlprovider/resolver.go | 16 ++-- providers/xmlprovider/xmlprovider.go | 33 +++------ viewmodels/agent_view.go | 19 +++-- viewmodels/year_view.go | 2 - xmlmodels/common.go | 7 ++ xmlmodels/library.go | 12 +-- xmlmodels/pieces.go | 106 +++++++++++++++++++++++++++ xmlmodels/references.go | 37 ++++++++-- xmlmodels/works.go | 28 ++++--- 10 files changed, 225 insertions(+), 64 deletions(-) create mode 100644 providers/xmlprovider/models.go diff --git a/providers/xmlprovider/models.go b/providers/xmlprovider/models.go new file mode 100644 index 0000000..e849c6c --- /dev/null +++ b/providers/xmlprovider/models.go @@ -0,0 +1,29 @@ +package xmlprovider + +import "fmt" + +type XMLItem interface { + fmt.Stringer + Keys() []string + Name() string +} + +type ILibrary interface { + Parse(meta ParseMeta) error +} + +type ResolvingMap[T XMLItem] map[string][]Resolved[T] + +type ReferenceResolver[T XMLItem] interface { + References() ResolvingMap[T] +} + +type Resolved[T XMLItem] struct { + Item *T + Reference string + Category string + Cert bool + Conjecture bool + Comment string + MetaData map[string]string +} diff --git a/providers/xmlprovider/resolver.go b/providers/xmlprovider/resolver.go index 9106585..d2aa714 100644 --- a/providers/xmlprovider/resolver.go +++ b/providers/xmlprovider/resolver.go @@ -7,30 +7,26 @@ import ( "sync" ) -type ReferenceResolver interface { - GetReferences() map[string][]string -} - type Resolver[T XMLItem] struct { - index map[string]map[string][]*T // Map[typeName][refID] -> []*T - mu sync.Mutex // Synchronization for thread safety + index map[string]map[string][]Resolved[T] // Map[typeName][refID] -> []*T + mu sync.Mutex // Synchronization for thread safety } func NewResolver[T XMLItem]() *Resolver[T] { - return &Resolver[T]{index: make(map[string]map[string][]*T)} + return &Resolver[T]{index: make(map[string]map[string][]Resolved[T])} } -func (r *Resolver[T]) Add(typeName, refID string, item *T) { +func (r *Resolver[T]) Add(typeName, refID string, item Resolved[T]) { r.mu.Lock() defer r.mu.Unlock() if _, exists := r.index[typeName]; !exists { - r.index[typeName] = make(map[string][]*T) + r.index[typeName] = make(map[string][]Resolved[T]) } r.index[typeName][refID] = append(r.index[typeName][refID], item) } -func (r *Resolver[T]) Get(typeName, refID string) ([]*T, error) { +func (r *Resolver[T]) Get(typeName, refID string) ([]Resolved[T], error) { r.mu.Lock() defer r.mu.Unlock() diff --git a/providers/xmlprovider/xmlprovider.go b/providers/xmlprovider/xmlprovider.go index 672e6d1..2e82b54 100644 --- a/providers/xmlprovider/xmlprovider.go +++ b/providers/xmlprovider/xmlprovider.go @@ -34,17 +34,6 @@ func (p ParseMeta) Failed(path string) bool { return slices.Contains(p.FailedPaths, path) } -type XMLItem interface { - fmt.Stringer - Keys() []string - Name() string -} - -type ILibrary interface { - Parse(meta ParseMeta) error - Latest() *ParseMeta -} - // An XMLProvider is a struct that holds holds serialized XML data of a specific type. It combines multiple parses IF a succeeded parse can not serialize the data from a path. type XMLProvider[T XMLItem] struct { // INFO: map is type map[string]*T @@ -72,7 +61,8 @@ func NewXMLProvider[T XMLItem]() *XMLProvider[T] { func (p *XMLProvider[T]) Prepare() { p.mu.Lock() defer p.mu.Unlock() - p.Array = make([]T, 0) + // INFO: We take 1000 here as to not reallocate the memory as mutch. + p.Array = make([]T, 0, 1000) } func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string, latest ParseMeta) error { @@ -94,13 +84,14 @@ func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string, la } // INFO: If the item has a GetReferences method, we add the references to the resolver. - // if refResolver, ok := any(item).(ReferenceResolver); ok { - // for name, ids := range refResolver.GetReferences() { - // for _, id := range ids { - // p.Resolver.Add(name, id, &item) - // } - // } - // } + if rr, ok := any(item).(ReferenceResolver[T]); ok { + for name, ids := range rr.References() { + for _, res := range ids { + res.Item = &item + p.Resolver.Add(name, res.Reference, res) + } + } + } } p.Array = append(p.Array, newItems...) @@ -144,7 +135,7 @@ func (p *XMLProvider[T]) Cleanup(latest ParseMeta) { } } -func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]*T, error) { +func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]Resolved[T], error) { keys := item.Keys() if len(keys) == 0 { @@ -158,7 +149,7 @@ func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]*T, error) { } } - return []*T{}, nil + return []Resolved[T]{}, nil } func (a *XMLProvider[T]) String() string { diff --git a/viewmodels/agent_view.go b/viewmodels/agent_view.go index 04b0764..753dcaa 100644 --- a/viewmodels/agent_view.go +++ b/viewmodels/agent_view.go @@ -64,14 +64,17 @@ func AgentsView(letterorid string, lib *xmlmodels.Library) *AgentsListView { // TODO: We won't need to lock the library if we take down the server during parsing lib.Works.Lock() - for _, w := range lib.Works.Array { - if ref, ok := w.ReferencesAgent(letterorid); ok { - if entry, ok := res.Agents[ref.Ref]; ok { - entry.Works = append(entry.Works, WorkByAgent{Work: w, Reference: *ref}) - res.Agents[ref.Ref] = entry - } - } - } + // for _, a := range res.Agents { + // + // } + // for _, w := range lib.Works.Array { + // if ref, ok := w.ReferencesAgent(letterorid); ok { + // if entry, ok := res.Agents[ref.Ref]; ok { + // entry.Works = append(entry.Works, WorkByAgent{Work: w, Reference: *ref}) + // res.Agents[ref.Ref] = entry + // } + // } + // } lib.Works.Unlock() lib.Pieces.Lock() diff --git a/viewmodels/year_view.go b/viewmodels/year_view.go index 7185c5a..4cf9718 100644 --- a/viewmodels/year_view.go +++ b/viewmodels/year_view.go @@ -2,7 +2,6 @@ package viewmodels import ( "fmt" - "log" "maps" "slices" "sort" @@ -33,7 +32,6 @@ func YearView(year int, lib *xmlmodels.Library) (*YearVM, error) { lib.Issues.Lock() for _, issue := range lib.Issues.Array { - log.Printf("Issue: %v", issue) y := issue.Datum.When.Year years[y] = true if y == year { diff --git a/xmlmodels/common.go b/xmlmodels/common.go index bc49551..719342a 100644 --- a/xmlmodels/common.go +++ b/xmlmodels/common.go @@ -61,6 +61,13 @@ func (i Identifier) Keys() []string { return i.keys } +type Reference struct { + Ref string `xml:"ref,attr"` + Category string `xml:"kat,attr"` + Unsicher bool `xml:"unsicher,attr"` + Inner Inner +} + type Value struct { Chardata string `xml:",chardata"` } diff --git a/xmlmodels/library.go b/xmlmodels/library.go index 9a52976..2e429ee 100644 --- a/xmlmodels/library.go +++ b/xmlmodels/library.go @@ -40,12 +40,12 @@ func (l *Library) String() string { // INFO: this is the only place where the providers are created. There is no need for locking on access. func NewLibrary() *Library { return &Library{ - Agents: &xmlprovider.XMLProvider[Agent]{}, - Places: &xmlprovider.XMLProvider[Place]{}, - Works: &xmlprovider.XMLProvider[Work]{}, - Categories: &xmlprovider.XMLProvider[Category]{}, - Issues: &xmlprovider.XMLProvider[Issue]{}, - Pieces: &xmlprovider.XMLProvider[Piece]{}, + Agents: xmlprovider.NewXMLProvider[Agent](), + Places: xmlprovider.NewXMLProvider[Place](), + Works: xmlprovider.NewXMLProvider[Work](), + Categories: xmlprovider.NewXMLProvider[Category](), + Issues: xmlprovider.NewXMLProvider[Issue](), + Pieces: xmlprovider.NewXMLProvider[Piece](), } } diff --git a/xmlmodels/pieces.go b/xmlmodels/pieces.go index 662cdcf..a34f4dc 100644 --- a/xmlmodels/pieces.go +++ b/xmlmodels/pieces.go @@ -6,6 +6,7 @@ import ( "strconv" "strings" + "github.com/Theodor-Springmann-Stiftung/kgpz_web/providers/xmlprovider" "github.com/google/uuid" ) @@ -66,6 +67,111 @@ func (p Piece) ReferencesIssue(y, no int) (*IssueRef, bool) { return nil, false } +func (p Piece) References() xmlprovider.ResolvingMap[Piece] { + refs := make(xmlprovider.ResolvingMap[Piece]) + x := CategoryRef{} + + for _, ref := range p.IssueRefs { + if ref.When.Year == 0 || ref.Nr == 0 { + continue + } + if ref.Category != "" { + refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + }) + } + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{ + Reference: strconv.Itoa(ref.When.Year) + "-" + strconv.Itoa(ref.Nr), + Category: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + MetaData: map[string]string{"Von": strconv.Itoa(ref.Von), "Bis": strconv.Itoa(ref.Bis)}, + }) + } + + for _, ref := range p.PlaceRefs { + if ref.Category != "" { + refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + }) + } + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Ref, + Category: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + MetaData: map[string]string{}, + }) + } + + for _, ref := range p.AgentRefs { + if ref.Category != "" { + refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + }) + } + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Ref, + Category: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + MetaData: map[string]string{}, + }) + } + + for _, ref := range p.WorkRefs { + if ref.Category != "" { + refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + }) + } + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Ref, + Category: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + MetaData: map[string]string{}, + }) + } + + for _, ref := range p.PieceRefs { + if ref.Category != "" { + refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + MetaData: map[string]string{}, + }) + } + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{ + Reference: ref.Ref, + Category: ref.Category, + Cert: !ref.Unsicher, + Conjecture: false, + Comment: ref.Inner.InnerXML, + MetaData: map[string]string{}, + }) + } + + return refs +} + func (p Piece) ReferencesAgent(a string) (*AgentRef, bool) { for _, i := range p.AgentRefs { if strings.HasPrefix(i.Ref, a) { diff --git a/xmlmodels/references.go b/xmlmodels/references.go index b66d3ce..cd1c582 100644 --- a/xmlmodels/references.go +++ b/xmlmodels/references.go @@ -2,18 +2,16 @@ package xmlmodels import "encoding/xml" -type Reference struct { - Ref string `xml:"ref,attr"` - Category string `xml:"kat,attr"` - Unsicher bool `xml:"unsicher,attr"` - Value -} - type AgentRef struct { XMLName xml.Name `xml:"akteur"` Reference } +func (ar AgentRef) Name() string { + var x Agent + return x.Name() +} + type IssueRef struct { XMLName xml.Name `xml:"stueck"` Nr int `xml:"nr,attr"` @@ -24,24 +22,49 @@ type IssueRef struct { Reference // Nicht im Schema } +func (ir IssueRef) Name() string { + var x Issue + return x.Name() +} + type PlaceRef struct { XMLName xml.Name `xml:"ort"` Reference } +func (pr PlaceRef) Name() string { + var x Place + return x.Name() +} + type CategoryRef struct { XMLName xml.Name `xml:"kategorie"` Reference } +func (cr CategoryRef) Name() string { + var x Category + return x.Name() +} + type WorkRef struct { XMLName xml.Name `xml:"werk"` Page string `xml:"s,attr"` Reference } +func (wr WorkRef) Name() string { + var x Work + return x.Name() +} + type PieceRef struct { XMLName xml.Name `xml:"beitrag"` Page string `xml:"s,attr"` Reference } + +func (pr PieceRef) Name() string { + var x Piece + return x.Name() +} diff --git a/xmlmodels/works.go b/xmlmodels/works.go index 68199f9..800110f 100644 --- a/xmlmodels/works.go +++ b/xmlmodels/works.go @@ -3,7 +3,8 @@ package xmlmodels import ( "encoding/json" "encoding/xml" - "strings" + + "github.com/Theodor-Springmann-Stiftung/kgpz_web/providers/xmlprovider" ) type Work struct { @@ -20,15 +21,6 @@ func (w Work) Name() string { return "work" } -func (p Work) ReferencesAgent(a string) (*AgentRef, bool) { - for _, i := range p.AgentRefs { - if strings.HasPrefix(i.Ref, a) { - return &i, true - } - } - return nil, false -} - type Citation struct { XMLName xml.Name `xml:"zitation"` Title string `xml:"title"` @@ -37,6 +29,22 @@ type Citation struct { Inner } +func (w Work) References() xmlprovider.ResolvingMap[Work] { + refs := make(xmlprovider.ResolvingMap[Work]) + + for _, ref := range w.AgentRefs { + refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Work]{ + Item: &w, // Reference to the current Work item + Reference: ref.Ref, // Reference ID + Category: ref.Category, // Category of the reference + Cert: !ref.Unsicher, // Certainty flag (true if not unsure) + Conjecture: false, + Comment: ref.Inner.InnerXML, + }) + } + + return refs +} func (w Work) String() string { data, _ := json.MarshalIndent(w, "", " ") return string(data)