Skip to content

structaccess: reach fields of a doubly-embedded struct - #6467

Draft
denik wants to merge 4 commits into
mainfrom
denik/structaccess-embedded-lookup
Draft

structaccess: reach fields of a doubly-embedded struct#6467
denik wants to merge 4 commits into
mainfrom
denik/structaccess-embedded-lookup

Conversation

@denik

@denik denik commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

The value-level field lookup descended one level into embedded structs, so a field two levels down was reported "not found" — every postgres resource has that shape (PostgresProjectPostgresProjectConfigpostgres.ProjectSpec). The type-level lookup was already recursive, so ValidatePath and Get disagreed.

The search is breadth-first, matching encoding/json: JSON picks the shallowest field of a given name, so a depth-first search could resolve a path to a deeper field than the one that gets serialized.

No product path reaches this today — the direct engine reads fields out of the state and remote types, where spec fields sit one level down. bundle/internal/schema/parser.go and libs/dyn/convert/struct_info.go already walk past level 1 for exactly this shape; structaccess was the holdout.

This pull request and its description were written by Isaac.

FindStructFieldByKeyType already recursed into embedded structs, but Get and Set
stopped after one level, so a field of resources.PostgresProject -- which embeds
a config struct that embeds the SDK spec -- was reported as not found.

Both now walk embedding recursively and track the struct that declares the field,
which is also the one whose ForceSendFields governs it: an outer struct that
shadows the name (PostgresProjectConfig) tracks only its own fields.

Co-authored-by: Isaac
… does

From the adversarial review. Get and Set searched embedded structs depth-first, so a name
declared at two embedding depths could resolve to the deeper field -- while json.Marshal
picks the shallower one. Reading and writing the field would then not be the field that
gets serialized under that name.

The search now goes one level of embedding at a time, and the test fails on the old
behaviour.

Co-authored-by: Isaac
…tree

Follow-up to the earlier fix, which only separated the first level of embedding from the
rest: a field three levels down in the first anonymous member still won over the same name
two levels down in a later member, while encoding/json picks the shallower one.

ValidatePattern had the same depth-first walk, so a path could validate against one field
and then be read and written on another. Both now walk level by level and share the
direct-field scan.

Co-authored-by: Isaac
The ForceSendFields assertion reads the promoted field, and the comparison
spells out that GetByString returns the empty string rather than nil -- an
explicit "" and an absent field are not the same thing.
@denik
denik force-pushed the denik/structaccess-embedded-lookup branch from 7cb774c to 79f9b61 Compare September 2, 2026 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant