Skip to content

[ENHANCEMENT](pyspark) Generalize field_path to arbitrary map/array nesting#572

Open
Seth Fitzsimmons (sethfitz) wants to merge 3 commits into
pyspark-expression-codegenfrom
generalize-field-path
Open

[ENHANCEMENT](pyspark) Generalize field_path to arbitrary map/array nesting#572
Seth Fitzsimmons (sethfitz) wants to merge 3 commits into
pyspark-expression-codegenfrom
generalize-field-path

Conversation

@sethfitz

@sethfitz Seth Fitzsimmons (sethfitz) commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Implements #570 — generalize field_path to arbitrary map/array nesting.

What changed

Collapses field_path's three-class taxonomy (ScalarPath/ArrayPath/MapPath) into Direct + Iterated, extends the grammar to interleaved map/array markers, and replaces the four array/map wrap functions with one _wrap_in_iteration fold over RenderFrames. A container nested directly inside another with no field name between them is an anonymous iterating segment, so list[list[X]], dict[K, list], list[dict], nested maps, and maps reached through arrays are now representable and render working validation end-to-end. Adds the flattening runtime pair nested_map_{keys,values}_check.

Notes

The generated-conformance-test path now handles mixed map/array shapes: a field check on a map value/key reached through array iteration (items[].tags{value}) descends the array and mutates the right map side, ground-truthed against real Spark. The remaining mixed shapes with no in-place mutation (subs{value}[], items[].configs{value}) are loud capability gates, not silent misroutes.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown

🗺️ Schema reference docs preview is live!

🌍 Preview https://staging.overturemaps.org/schema/pr/572/schema/index.html
🕐 Updated Jul 20, 2026 20:59 UTC
📝 Commit 0d507b8
🔧 env SCHEMA_PREVIEW true

Note

♻️ This preview updates automatically with each push to this PR.

Collapse field_path's ScalarPath/ArrayPath/MapPath taxonomy into Direct
+ Iterated and extend the grammar to interleaved map/array markers. A
container nested directly inside another with no field name between
(list[list[X]], dict[K, list[X]], list[dict], nested maps, a map reached
through an array) becomes an anonymous iterating segment, so every such
shape is now representable and renders, validates, and mutates end to
end.

Replace the four array/map wrap functions with one _wrap_in_iteration
fold over RenderFrames, and add the flattening runtime pair
nested_map_{keys,values}_check. Remove the union-under-multi-list and
newtype-under-list guards -- those shapes render correctly now -- and
add a guard for a union variant field reached through iteration past its
discriminator element, where the ElementGuard would gate the wrong
element.

The generated-conformance-test path handles the new shapes: set_at_path
learns the {value}/{key} grammar and descends trailing containers; model
mutations gain a composite element_path for map-then-array and
array-then-map nesting; shapes with no in-place mutation are loud
capability gates, not silent misroutes.

Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
A model-level constraint declared on a submodel reached through a plain
struct field -- @require_any_of on Details where Feature.details:
Details -- now anchors at the struct prefix instead of collapsing to the
row root.  _model_constraint_target is the identity on the prefix; the
renderer qualifies every field and condition reference with that prefix
(F.col("details.foo")) and gates an optional struct on presence
(F.when(F.col("details").isNotNull(), ...)). ModelCheck.read_columns
reads the single top-level struct column.

_guard_struct_nested_anchor narrows to struct-nested discriminated
unions only: their variant ColumnGuards render the discriminator as a
top-level column, which a struct-qualified path cannot express. Plain
struct-nested model constraints are now supported and no longer raise.

Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
Rewrite the Check Builder section of the codegen design doc for the
current Direct/Iterated FieldPath taxonomy: anonymous segments, the
single _wrap_in_iteration fold, and the mixed map/array nesting cases
(dict[K, list], list[dict], nested maps, map-in-array), replacing the
retired ScalarPath/ArrayPath/MapPath description. Disambiguate
iter_frames (named-only structural folding) from the renderer's
per-segment _render_frames walk.

Signed-off-by: Seth Fitzsimmons <seth@mojodna.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant