Prepare reusable inheritance scope execution
This commit is contained in:
178
internal/engine/inheritance_scope.go
Normal file
178
internal/engine/inheritance_scope.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package engine
|
||||
|
||||
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
|
||||
|
||||
// inheritanceScopeAdapter keeps relationship execution independent from the
|
||||
// container that owns the records. Adapters are private preparation machinery;
|
||||
// public loading continues to use mapping scopes until record inheritance is
|
||||
// activated separately.
|
||||
type inheritanceScopeAdapter interface {
|
||||
scope() *document.Node
|
||||
scopePath() Path
|
||||
collectionPolicies() collectionPolicyScope
|
||||
applicationPolicy() sequencePolicy
|
||||
templates() []inheritanceExecutionTemplate
|
||||
slots() []inheritanceScopeSlot
|
||||
slotOverhead() int
|
||||
rebuild(resolved []*document.Node) *document.Node
|
||||
}
|
||||
|
||||
type inheritanceExecutionTemplate struct {
|
||||
entry document.Entry
|
||||
path Path
|
||||
collectionPolicies collectionPolicyScope
|
||||
parent int
|
||||
hasParent bool
|
||||
hasDirective bool
|
||||
cancelled bool
|
||||
directive document.Entry
|
||||
directivePath Path
|
||||
identityFields []string
|
||||
}
|
||||
|
||||
type inheritanceScopeSlot struct {
|
||||
value *document.Node
|
||||
path Path
|
||||
template int
|
||||
hasTemplate bool
|
||||
}
|
||||
|
||||
type mappingInheritanceScope struct{ graph *inheritanceGraph }
|
||||
|
||||
func (scope mappingInheritanceScope) scope() *document.Node { return scope.graph.scope }
|
||||
func (scope mappingInheritanceScope) scopePath() Path { return scope.graph.scopePath }
|
||||
func (scope mappingInheritanceScope) collectionPolicies() collectionPolicyScope {
|
||||
return scope.graph.collectionPolicies
|
||||
}
|
||||
func (scope mappingInheritanceScope) applicationPolicy() sequencePolicy {
|
||||
return scope.graph.applicationPolicy
|
||||
}
|
||||
func (scope mappingInheritanceScope) slotOverhead() int { return 1 }
|
||||
func (scope mappingInheritanceScope) templates() []inheritanceExecutionTemplate {
|
||||
result := make([]inheritanceExecutionTemplate, len(scope.graph.nodes))
|
||||
for index, node := range scope.graph.nodes {
|
||||
var directive document.Entry
|
||||
if node.hasDirective {
|
||||
directive = node.directive
|
||||
}
|
||||
result[index] = inheritanceExecutionTemplate{
|
||||
entry: node.entry, path: node.path,
|
||||
collectionPolicies: node.collectionPolicies, parent: node.parent,
|
||||
hasParent: node.hasParent, hasDirective: node.hasDirective,
|
||||
cancelled: node.cancelled, directive: directive,
|
||||
directivePath: node.path.Key(inheritanceKey),
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
func (scope mappingInheritanceScope) slots() []inheritanceScopeSlot {
|
||||
result := make([]inheritanceScopeSlot, len(scope.graph.scope.Mapping))
|
||||
for index, entry := range scope.graph.scope.Mapping {
|
||||
slot := inheritanceScopeSlot{
|
||||
value: entry.Value, path: scope.graph.scopePath.Key(entry.Key),
|
||||
}
|
||||
if template, ok := scope.graph.byName[entry.Key]; ok {
|
||||
slot.template, slot.hasTemplate = template, true
|
||||
}
|
||||
result[index] = slot
|
||||
}
|
||||
return result
|
||||
}
|
||||
func (scope mappingInheritanceScope) rebuild(resolved []*document.Node) *document.Node {
|
||||
root := *scope.graph.scope
|
||||
root.Mapping = make([]document.Entry, len(scope.graph.scope.Mapping))
|
||||
for index, entry := range scope.graph.scope.Mapping {
|
||||
root.Mapping[index] = entry
|
||||
if template, ok := scope.graph.byName[entry.Key]; ok {
|
||||
root.Mapping[index].Value = resolved[template]
|
||||
} else {
|
||||
root.Mapping[index].Value = document.Clone(entry.Value)
|
||||
}
|
||||
}
|
||||
return &root
|
||||
}
|
||||
|
||||
type identifiedSequenceInheritanceScope struct {
|
||||
graph *identifiedInheritanceGraph
|
||||
policies collectionPolicyScope
|
||||
application sequencePolicy
|
||||
}
|
||||
|
||||
func (scope identifiedSequenceInheritanceScope) scope() *document.Node { return scope.graph.scope }
|
||||
func (scope identifiedSequenceInheritanceScope) scopePath() Path { return scope.graph.scopePath }
|
||||
func (scope identifiedSequenceInheritanceScope) collectionPolicies() collectionPolicyScope {
|
||||
return scope.policies
|
||||
}
|
||||
func (scope identifiedSequenceInheritanceScope) applicationPolicy() sequencePolicy {
|
||||
return scope.application
|
||||
}
|
||||
func (scope identifiedSequenceInheritanceScope) slotOverhead() int { return 0 }
|
||||
func (scope identifiedSequenceInheritanceScope) templates() []inheritanceExecutionTemplate {
|
||||
result := make([]inheritanceExecutionTemplate, len(scope.graph.nodes))
|
||||
for index, node := range scope.graph.nodes {
|
||||
result[index] = inheritanceExecutionTemplate{
|
||||
entry: document.Entry{Value: node.item}, path: node.path,
|
||||
collectionPolicies: inheritancePolicyScopeAtPath(scope.policies, node.path),
|
||||
parent: node.parent, hasParent: node.hasParent,
|
||||
hasDirective: node.directive != nil, cancelled: node.cancelled,
|
||||
directive: document.Entry{Value: node.directive}, directivePath: node.directivePath,
|
||||
identityFields: scope.graph.fields,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
func (scope identifiedSequenceInheritanceScope) slots() []inheritanceScopeSlot {
|
||||
result := make([]inheritanceScopeSlot, len(scope.graph.nodes))
|
||||
for index, node := range scope.graph.nodes {
|
||||
result[index] = inheritanceScopeSlot{
|
||||
value: node.item, path: node.path, template: index, hasTemplate: true,
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
func (scope identifiedSequenceInheritanceScope) rebuild(resolved []*document.Node) *document.Node {
|
||||
root := *scope.graph.scope
|
||||
root.Sequence = make([]*document.Node, len(scope.graph.nodes))
|
||||
for index := range root.Sequence {
|
||||
root.Sequence[index] = resolved[index]
|
||||
}
|
||||
return &root
|
||||
}
|
||||
|
||||
func preserveInheritanceIdentityFields(merged, child *document.Node, fields []string) {
|
||||
if len(fields) == 0 || merged == nil || merged.Kind != document.Mapping || child == nil || child.Kind != document.Mapping {
|
||||
return
|
||||
}
|
||||
for _, field := range fields {
|
||||
for _, entry := range child.Mapping {
|
||||
if entry.Key != field {
|
||||
continue
|
||||
}
|
||||
for index := range merged.Mapping {
|
||||
if merged.Mapping[index].Key == field {
|
||||
merged.Mapping[index] = document.Entry{Key: field, Value: document.Clone(entry.Value)}
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func applyIdentifiedInheritanceTemplates(
|
||||
graph *identifiedInheritanceGraph,
|
||||
limits projectionLimits,
|
||||
inputOrigins map[string]Origin,
|
||||
policies collectionPolicyScope,
|
||||
application sequencePolicy,
|
||||
budget ...*retainedNodeCounter,
|
||||
) (*inheritanceScope, []Diagnostic) {
|
||||
order, diagnostics := graph.schedule()
|
||||
if len(diagnostics) != 0 {
|
||||
return nil, diagnostics
|
||||
}
|
||||
adapter := identifiedSequenceInheritanceScope{
|
||||
graph: graph, policies: policies, application: application,
|
||||
}
|
||||
return applyInheritanceScopeTemplates(adapter, order, limits, inputOrigins, budget...)
|
||||
}
|
||||
Reference in New Issue
Block a user