support flattened map struct binding in strict mode#43
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Adds full support for binding map[string]Struct from flattened dotted keys produced by the file source, while updating strict-mode unknown-key validation to permit valid dynamic map-entry keys and adding regression tests.
Changes:
- Extend strict-mode unknown-key checking to allow dotted keys that match
map[string]Tentry patterns (including nested struct fields). - Synthesize nested map values from flattened dotted keys during binding when the base map key isn’t present.
- Add loader regression tests for flattened map binding, strict-mode behavior, and invalid type conversion.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| loader.go | Adds dynamic map-key pattern collection/matching to strict-mode unknown key validation. |
| binding.go | Synthesizes nested map entries from flattened dotted keys; adjusts provenance recording for synthesized entries. |
| loader_test.go | Adds tests covering flattened map[string]Struct binding and strict-mode validation behavior. |
Comments suppressed due to low confidence (1)
binding.go:560
- In synthesizeNestedMapEntry,
mixedSourcesis set when eithersourceNameorsourceKeydiffers. For env sources,sourceKeyis per-variable (e.g.env:APP_FOO), so a synthesized map built entirely from env vars will be treated as “mixed” and provenance gets cleared even though all entries come from the same source. Consider treating the map as mixed only whensourceNamediffers; when onlysourceKeydiffers, keepsourceNameand clearsourceKeyso the map field still reports it came from the env/file source (without pretending a single variable/key produced the whole map).
var sourceName string
var sourceKey string
found := false
mixedSources := false
for dataKey, entry := range data {
if !strings.HasPrefix(dataKey, prefix) {
continue
}
parts := strings.Split(strings.TrimPrefix(dataKey, prefix), ".")
if len(parts) == 0 || parts[0] == "" {
continue
}
setNestedMapValue(nested, parts, entry.value)
if !found {
sourceName = entry.sourceName
sourceKey = entry.sourceKey
found = true
continue
}
if sourceName != entry.sourceName || sourceKey != entry.sourceKey {
mixedSources = true
}
}
if !found {
return mergedEntry{}, false
}
if mixedSources {
// A single field-level provenance source would be misleading for a synthesized mixed-source map.
sourceName = ""
sourceKey = ""
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Azhovan
previously approved these changes
Feb 23, 2026
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
loader.go:327
- After unwrapping an Optional type, the inner type should be checked for pointers and dereferenced if necessary before the struct check. Currently, if valueType is Optional[*StructType], the code would get the *StructType but not dereference it before checking if it's a struct at line 329. Consider adding pointer dereferencing after unwrapping Optional types to handle edge cases like Optional[*StructType] or Optional[map[string]*StructType].
if isOptionalType(valueType) {
valueType = valueType.Field(0).Type
}
loader.go:282
- After unwrapping an Optional type at line 281, the inner type should be checked for pointers and dereferenced if necessary. Currently, if unwrappedType is Optional[*MapType] or Optional[*StructType], the code would not properly dereference the pointer before checking the kind. Consider adding pointer dereferencing after line 282 to handle these edge cases.
if isOptionalType(unwrappedType) {
unwrappedType = unwrappedType.Field(0).Type
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Azhovan
approved these changes
Feb 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Complete nested collection binding support for
map[string]TwhereTis a struct in the built-in file-source flattening path:[]TwhereTis a struct from YAML-decoded collection values (existing support from the prior patch remains).map[string]TwhereTis a struct from:clickhouse_map.primary.host).map[string]Tfields while still rejecting unknown nested fields.map[string]TStrict(false)behaviorinvalid_type)Docs: Updated
docs/configuration-sources.md(anddocs/api-reference.mdif included) with amap[string]StructYAML example and behavior notes.Why
Rigging’s file source flattens nested YAML maps into dotted keys (for example,
clickhouse_map.primary.host), which previously prevented binding intomap[string]Structfields and caused strict-mode false positives for valid nested keys.This PR completes support for a common typed YAML config shape while preserving existing public APIs and source precedence behavior.
Type
Testing
Executed:
Checklist
[x] Tests pass (go test ./...)
[x] Formatted (gofmt -s -w .)
[x] No vet warnings (go vet ./...)
[x] Coverage maintained (>70%)
[x] Added tests if needed
[x] Updated docs if needed
fully addresses #33