Files
ConfigKit/internal/engine/collection_retirement.go

82 lines
2.7 KiB
Go

package engine
import "gitea.maximumdirect.net/eric/ConfigKit/internal/document"
// A true entry replaces the collection itself as well as its descendants;
// false records ordinary ancestor replacement without selecting a collection
// operation at that exact path.
type collectionReplacementPaths map[string]bool
func (paths collectionReplacementPaths) contains(path Path, includeExact bool) bool {
for length := 0; length <= len(path.segments); length++ {
prefix := Path{segments: path.segments[:length]}
inclusive, found := paths[prefix.String()]
if found && (length < len(path.segments) || includeExact && inclusive) {
return true
}
}
return false
}
// lowerCollectionPoliciesForClaims makes replacement eligibility independent of
// declaration order. It removes only old YAML identity/record state; new pending
// declarations and application constraints are reconciled afterward.
func lowerCollectionPoliciesForClaims(
lower collectionPolicyScope,
claims []compositionClaim,
declarations map[string][]sequenceDeclarationSpec,
application sequencePolicy,
) (collectionPolicyScope, collectionReplacementPaths) {
byPath := make(map[string]compositionClaim, len(claims))
rootPath := ""
if len(claims) != 0 {
rootPath = claims[0].path.String()
}
for _, claim := range claims {
byPath[claim.path.String()] = claim
}
replaced := make(collectionReplacementPaths)
for key, claim := range byPath {
old, hasOld := lower.collections[key]
current := declarations[key]
if claim.kind == document.Mapping && (key == rootPath || !hasOld && len(current) == 0) {
continue // Ordinary mapping combination preserves descendants.
}
mode := sequenceMode(0)
identity := old.policy.identityPresent
for _, declaration := range current {
identity = identity || declaration.identityPresent
if mode == 0 && declaration.modePresent {
mode = declaration.mode
}
}
retainedMode := sequenceMode(0)
if old.policy.explicitModePresent {
retainedMode = old.policy.explicitMode
}
_, registered := application.identityFieldsAt(claim.path)
mode = collectionOperationMode(mode, retainedMode, identity || registered)
if mode == sequenceModeReplace {
replaced[key] = true
} else if claim.kind != document.Mapping && claim.kind != document.Sequence {
replaced[key] = false
}
}
result := cloneCollectionPolicyScope(lower)
for key, entry := range result.collections {
if replaced.contains(entry.destination, true) {
clearCollectionIdentity(&entry.policy)
result.collections[key] = entry
}
}
return result, replaced
}
func clearCollectionIdentity(policy *collectionPolicy) {
policy.identityFields = nil
policy.identityPresent = false
policy.identityLocation = nil
policy.recordOrder = nil
policy.recordPolicies = nil
}