Add dynamic sequence identity selectors

This commit is contained in:
2026-10-23 13:55:25 +00:00
parent 64c51647f0
commit 298e70b552
4 changed files with 451 additions and 41 deletions

View File

@@ -228,7 +228,7 @@ func validateRegisteredSequences(claims []compositionClaim, policy sequencePolic
if claim.kind != document.Sequence {
continue
}
identityField, registered := policy.identityFields[claim.path.String()]
identityFields, registered := policy.identityFieldsAt(claim.path)
if !registered {
continue
}
@@ -254,36 +254,71 @@ func validateRegisteredSequences(claims []compositionClaim, policy sequencePolic
Path: itemPath, Message: "registered sequence items must be mappings", Primary: location,
}}
}
fieldIndex := documentEntryIndex(item.Mapping, identityField)
if fieldIndex < 0 {
location := publicLocation(item.Location)
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: itemPath, Message: "registered sequence item is missing its identity field",
Primary: &location,
}}
}
field := item.Mapping[fieldIndex].Value
if field == nil || field.Kind != document.String {
location := publicLocation(item.Mapping[fieldIndex].ValueLocation)
if field != nil {
location = publicLocation(field.Location)
var identity string
var identityLocation document.Location
if legacyField, legacy := policy.identityFields[claim.path.String()]; legacy {
fieldIndex := documentEntryIndex(item.Mapping, legacyField)
if fieldIndex < 0 {
location := publicLocation(item.Location)
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: itemPath, Message: "registered sequence item is missing its identity field",
Primary: &location,
}}
}
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: itemPath.Key(identityField), Message: "registered sequence identity must be a string",
Primary: &location,
}}
field := item.Mapping[fieldIndex].Value
if field == nil || field.Kind != document.String {
location := publicLocation(item.Mapping[fieldIndex].ValueLocation)
if field != nil {
location = publicLocation(field.Location)
}
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: itemPath.Key(legacyField), Message: "registered sequence identity must be a string",
Primary: &location,
}}
}
identity, identityLocation = field.Text, field.Location
} else {
mapping := newSequenceMappingIndex(item)
var locations []document.Location
var fieldName string
var fieldIndex int
identity, locations, fieldName, fieldIndex = mapping.identity(identityFields)
if fieldIndex == -1 {
location := publicLocation(item.Location)
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: itemPath.Key(fieldName), Message: "registered sequence item is missing an identity field",
Primary: &location,
}}
}
if fieldIndex == -2 || fieldIndex >= 0 {
location := publicLocation(item.Location)
fieldPath := itemPath.Key(fieldName)
if fieldIndex >= 0 {
location = publicLocation(item.Mapping[fieldIndex].ValueLocation)
if field := item.Mapping[fieldIndex].Value; field != nil {
location = publicLocation(field.Location)
}
}
return nil, nil, []Diagnostic{{
Code: CodeComposeInvalid, Severity: SeverityError,
Path: fieldPath, Message: "registered sequence identity fields must be scalar values",
Primary: &location,
}}
}
identityLocation = locations[0]
}
if first, duplicate := identities[field.Text]; duplicate {
current := publicLocation(field.Location)
if first, duplicate := identities[identity]; duplicate {
current := publicLocation(identityLocation)
return nil, nil, []Diagnostic{{
Code: CodeComposeConflict, Severity: SeverityError,
Path: claim.path.clone(), Message: "registered sequence contains duplicate identities",
Primary: &first, Related: []Location{current},
}}
}
identities[field.Text] = publicLocation(field.Location)
identities[identity] = publicLocation(identityLocation)
}
if itemsByPath[pathKey] == nil {
itemsByPath[pathKey] = make(map[int]validatedSequence)
@@ -328,11 +363,6 @@ func mergeDisjointMappingsAtPath(target, incoming *document.Node, path Path, ind
mergeComposedMappings(target, incoming, path, index, sourceIndex, policy, validated)
}
func (p sequencePolicy) registered(path Path) bool {
_, ok := p.identityFields[path.String()]
return ok
}
func cloneSequenceRanges(ranges []sequenceRange) []sequenceRange {
cloned := make([]sequenceRange, len(ranges))
for i, assigned := range ranges {