Improve D&D registry normalization efficiency
This commit is contained in:
@@ -5,7 +5,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/eric/notarius/internal/core/source"
|
||||
@@ -58,9 +57,13 @@ func ComparisonKey(value string) string {
|
||||
// available, leaving validation to report the problem instead of manufacturing
|
||||
// an ID.
|
||||
func DeriveID(name string, refs []source.SourceRef) string {
|
||||
comparisonName := ComparisonKey(name)
|
||||
anchor, ok := earliestReference(refs)
|
||||
if comparisonName == "" || !ok {
|
||||
return deriveIDFromAnchor(name, anchor, ok)
|
||||
}
|
||||
|
||||
func deriveIDFromAnchor(name string, anchor source.SourceRef, hasAnchor bool) string {
|
||||
comparisonName := ComparisonKey(name)
|
||||
if comparisonName == "" || !hasAnchor {
|
||||
return ""
|
||||
}
|
||||
|
||||
@@ -111,13 +114,14 @@ func ValidateRegistry(locations []dnd.Location) []Issue {
|
||||
if ComparisonKey(location.Name) == "" {
|
||||
issues = append(issues, Issue{Code: IssueEmptyCanonicalName, RecordIndex: recordIndex, Value: location.Name})
|
||||
}
|
||||
if _, ok := earliestReference(location.SourceRefs); !ok {
|
||||
anchor, hasAnchor := earliestReference(location.SourceRefs)
|
||||
if !hasAnchor {
|
||||
issues = append(issues, Issue{Code: IssueMissingEvidence, RecordIndex: recordIndex})
|
||||
}
|
||||
|
||||
if !IsValidID(location.ID) {
|
||||
issues = append(issues, Issue{Code: IssueInvalidID, RecordIndex: recordIndex, Value: location.ID})
|
||||
} else if expected := DeriveID(location.Name, location.SourceRefs); location.ID != expected {
|
||||
} else if expected := deriveIDFromAnchor(location.Name, anchor, hasAnchor); location.ID != expected {
|
||||
issues = append(issues, Issue{Code: IssueIDMismatch, RecordIndex: recordIndex, Value: location.ID})
|
||||
}
|
||||
if location.ID != "" {
|
||||
@@ -135,36 +139,28 @@ func ValidateRegistry(locations []dnd.Location) []Issue {
|
||||
}
|
||||
|
||||
func earliestReference(refs []source.SourceRef) (source.SourceRef, bool) {
|
||||
canonical := canonicalReferences(refs)
|
||||
if len(canonical) == 0 {
|
||||
return source.SourceRef{}, false
|
||||
var earliest source.SourceRef
|
||||
found := false
|
||||
for _, ref := range refs {
|
||||
if !validIdentityReference(ref) {
|
||||
continue
|
||||
}
|
||||
if !found || referenceLess(ref, earliest) {
|
||||
earliest = ref
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return canonical[0], true
|
||||
return earliest, found
|
||||
}
|
||||
|
||||
func canonicalReferences(refs []source.SourceRef) []source.SourceRef {
|
||||
canonical := make([]source.SourceRef, 0, len(refs))
|
||||
for _, ref := range refs {
|
||||
if validIdentityReference(ref) {
|
||||
canonical = append(canonical, ref)
|
||||
}
|
||||
func referenceLess(left, right source.SourceRef) bool {
|
||||
if left.SourceID != right.SourceID {
|
||||
return left.SourceID < right.SourceID
|
||||
}
|
||||
sort.Slice(canonical, func(left, right int) bool {
|
||||
if canonical[left].SourceID != canonical[right].SourceID {
|
||||
return canonical[left].SourceID < canonical[right].SourceID
|
||||
}
|
||||
if canonical[left].StartUnitID != canonical[right].StartUnitID {
|
||||
return canonical[left].StartUnitID < canonical[right].StartUnitID
|
||||
}
|
||||
return canonical[left].EndUnitID < canonical[right].EndUnitID
|
||||
})
|
||||
unique := canonical[:0]
|
||||
for _, ref := range canonical {
|
||||
if len(unique) == 0 || unique[len(unique)-1] != ref {
|
||||
unique = append(unique, ref)
|
||||
}
|
||||
if left.StartUnitID != right.StartUnitID {
|
||||
return left.StartUnitID < right.StartUnitID
|
||||
}
|
||||
return unique
|
||||
return left.EndUnitID < right.EndUnitID
|
||||
}
|
||||
|
||||
func validIdentityReference(ref source.SourceRef) bool {
|
||||
|
||||
Reference in New Issue
Block a user