Expose sequence identity registrations through the facade
This commit is contained in:
@@ -1,10 +1,5 @@
|
||||
package engine
|
||||
|
||||
type sequenceRegistration struct {
|
||||
path Path
|
||||
identityField string
|
||||
}
|
||||
|
||||
type sequenceSelectorSegmentKind uint8
|
||||
|
||||
const (
|
||||
@@ -22,6 +17,24 @@ type sequenceIdentitySelector []sequenceSelectorSegment
|
||||
type sequenceIdentityRegistration struct {
|
||||
selector sequenceIdentitySelector
|
||||
identityFields []string
|
||||
invalidPath *Path
|
||||
}
|
||||
|
||||
// SequenceIdentitySelectorSegment carries one root-owned selector segment into
|
||||
// an engine definition. This transport type remains behind the internal package
|
||||
// boundary.
|
||||
type SequenceIdentitySelectorSegment struct {
|
||||
Key string
|
||||
AnyMappingKey bool
|
||||
}
|
||||
|
||||
// SequenceIdentityRegistrationInput carries detached root-owned registration
|
||||
// data into an engine definition without exposing its compiled policy. A
|
||||
// non-nil ExactPath selects exact-path registration; otherwise Selector is used.
|
||||
type SequenceIdentityRegistrationInput struct {
|
||||
ExactPath *Path
|
||||
Selector []SequenceIdentitySelectorSegment
|
||||
IdentityFields []string
|
||||
}
|
||||
|
||||
type sequenceSelectorTrie struct {
|
||||
@@ -32,62 +45,59 @@ type sequenceSelectorTrie struct {
|
||||
}
|
||||
|
||||
type sequencePolicy struct {
|
||||
// identityFields preserves the old exact-path view for existing internal
|
||||
// callers while selector matching is introduced behind the same policy.
|
||||
identityFields map[string]string
|
||||
selectorTrie *sequenceSelectorTrie
|
||||
selectorTrie *sequenceSelectorTrie
|
||||
}
|
||||
|
||||
// DefinitionWithSequenceRegistrations attaches facade-owned registrations to a
|
||||
// detached engine definition without exposing the registration representation.
|
||||
func DefinitionWithSequenceRegistrations[T any](definition Definition[T], paths []Path, identityFields []string) Definition[T] {
|
||||
if paths == nil {
|
||||
definition.sequenceRegistrations = nil
|
||||
// DefinitionWithSequenceIdentityRegistrations attaches facade-owned
|
||||
// registrations to a detached engine definition without exposing compiled
|
||||
// engine policy.
|
||||
func DefinitionWithSequenceIdentityRegistrations[T any](definition Definition[T], registrations []SequenceIdentityRegistrationInput) Definition[T] {
|
||||
if registrations == nil {
|
||||
definition.sequenceIdentityRegistrations = nil
|
||||
return definition
|
||||
}
|
||||
definition.sequenceRegistrations = make([]sequenceRegistration, len(paths))
|
||||
for index := range paths {
|
||||
definition.sequenceRegistrations[index] = sequenceRegistration{
|
||||
path: paths[index].clone(), identityField: identityFields[index],
|
||||
definition.sequenceIdentityRegistrations = make([]sequenceIdentityRegistration, len(registrations))
|
||||
for index, registration := range registrations {
|
||||
compiled := sequenceIdentityRegistration{identityFields: append([]string(nil), registration.IdentityFields...)}
|
||||
if registration.ExactPath != nil {
|
||||
path, err := normalizeDestination(registration.ExactPath.clone())
|
||||
if err != nil {
|
||||
invalid := registration.ExactPath.clone()
|
||||
compiled.invalidPath = &invalid
|
||||
} else {
|
||||
compiled.selector = make(sequenceIdentitySelector, len(path.segments))
|
||||
for segmentIndex, segment := range path.segments {
|
||||
compiled.selector[segmentIndex] = sequenceSelectorSegment{kind: sequenceSelectorLiteral, key: segment.key}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
compiled.selector = make(sequenceIdentitySelector, len(registration.Selector))
|
||||
for segmentIndex, segment := range registration.Selector {
|
||||
kind := sequenceSelectorLiteral
|
||||
if segment.AnyMappingKey {
|
||||
kind = sequenceSelectorAnyMappingKey
|
||||
}
|
||||
compiled.selector[segmentIndex] = sequenceSelectorSegment{kind: kind, key: segment.Key}
|
||||
}
|
||||
}
|
||||
definition.sequenceIdentityRegistrations[index] = compiled
|
||||
}
|
||||
return definition
|
||||
}
|
||||
|
||||
func compileSequencePolicy(registrations []sequenceRegistration) (sequencePolicy, []Diagnostic) {
|
||||
common := make([]sequenceIdentityRegistration, 0, len(registrations))
|
||||
var diagnostics []Diagnostic
|
||||
legacyPaths := make(map[string]string, len(registrations))
|
||||
for _, registration := range registrations {
|
||||
path, err := normalizeDestination(registration.path)
|
||||
if err != nil {
|
||||
diagnostics = append(diagnostics, Diagnostic{
|
||||
Code: CodeOptionsInvalid, Severity: SeverityError,
|
||||
Path: registration.path.clone(), Message: "sequence registration path must contain only non-reserved mapping keys",
|
||||
})
|
||||
continue
|
||||
}
|
||||
selector := make(sequenceIdentitySelector, len(path.segments))
|
||||
for index, segment := range path.segments {
|
||||
selector[index] = sequenceSelectorSegment{kind: sequenceSelectorLiteral, key: segment.key}
|
||||
}
|
||||
common = append(common, sequenceIdentityRegistration{
|
||||
selector: selector, identityFields: []string{registration.identityField},
|
||||
})
|
||||
legacyPaths[path.String()] = registration.identityField
|
||||
}
|
||||
policy, compiledDiagnostics := compileSequenceIdentityPolicy(common)
|
||||
policy.identityFields = legacyPaths
|
||||
diagnostics = append(diagnostics, compiledDiagnostics...)
|
||||
return policy, canonicalDiagnostics(diagnostics)
|
||||
}
|
||||
|
||||
func compileSequenceIdentityPolicy(registrations []sequenceIdentityRegistration) (sequencePolicy, []Diagnostic) {
|
||||
policy := sequencePolicy{}
|
||||
compiled := make([]sequenceIdentityRegistration, 0, len(registrations))
|
||||
var diagnostics []Diagnostic
|
||||
for _, registration := range registrations {
|
||||
selector := cloneSequenceIdentitySelector(registration.selector)
|
||||
if registration.invalidPath != nil {
|
||||
diagnostics = append(diagnostics, Diagnostic{
|
||||
Code: CodeOptionsInvalid, Severity: SeverityError, Path: registration.invalidPath.clone(),
|
||||
Message: "sequence registration path must contain only non-reserved mapping keys",
|
||||
})
|
||||
continue
|
||||
}
|
||||
fields, err := normalizeSequenceIdentityFields(registration.identityFields)
|
||||
if err != nil {
|
||||
diagnostics = append(diagnostics, Diagnostic{
|
||||
@@ -172,11 +182,7 @@ func (p sequencePolicy) identityFieldsAt(path Path) ([]string, bool) {
|
||||
return nil, false
|
||||
}
|
||||
if p.selectorTrie == nil {
|
||||
field, ok := p.identityFields[path.String()]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
return []string{field}, true
|
||||
return nil, false
|
||||
}
|
||||
current := []*sequenceSelectorTrie{p.selectorTrie}
|
||||
for _, segment := range path.segments {
|
||||
|
||||
Reference in New Issue
Block a user