remove check for ash embedded resource (allow all types in attributes) - #1
Merged
Merged
Conversation
Reviewer's GuideThis PR fixes incorrect handling of typed structs used as attribute types by relaxing the embedded resource check, and adds a discriminated union example (Actor) with associated tests to ensure correct OpenAPI schema generation. File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- The
embedded_resource?/1helper now only checks forspark_is/0, which means it will treat any Spark DSL module (not just embedded Ash resources) as an embedded resource; either narrow the predicate (e.g., keep theSpark.Dsl.is?(type, Ash.Resource)check) or rename the function to reflect its broader semantics. - With the new behavior in
embedded_resource?/1, consider whether non-embedded resources or other DSL modules should now be handled differently downstream (e.g., when generating schemas) to avoid unexpected$refgeneration for types that are not actually embedded resources.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The `embedded_resource?/1` helper now only checks for `spark_is/0`, which means it will treat any Spark DSL module (not just embedded Ash resources) as an embedded resource; either narrow the predicate (e.g., keep the `Spark.Dsl.is?(type, Ash.Resource)` check) or rename the function to reflect its broader semantics.
- With the new behavior in `embedded_resource?/1`, consider whether non-embedded resources or other DSL modules should now be handled differently downstream (e.g., when generating schemas) to avoid unexpected `$ref` generation for types that are not actually embedded resources.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
…alize_complex_type
Resolves the type_mapper conflict on top of the 0.2.0 rewrite: - keep the json_schema/1-callback-before-embedded reorder from this branch - detect typed structs precisely as NewTypes of Ash.Type.Struct (instead of the spark_is/0 check, which matches any Spark DSL module) and build object schemas from the NewType's field constraints, so declared field types are kept (integer stays integer) and allow_nil? false fields become required - mark the actor fixture public? true per the 0.2.0 visibility rules, add a direct typed-struct attribute (owner), and extend the tests: corrected variant assertions, 3.0 coverage, and Oaskit validation of the Lab domain spec in both versions
futhr
added a commit
that referenced
this pull request
Jun 10, 2026
setup-beam resolves "28" to the latest patch build, and a PLT created on an older patch (28.5.0.1) fails with "Old PLT file" once a newer one (28.5.0.2) ships — exactly what broke the dialyzer job on PR #1. Keying on the resolved versions makes a toolchain bump rebuild the PLT instead of failing.
Owner
|
Thanks for digging into this and for the clean repro with the Person/Company union, that made the problem easy to verify. You were right that typed structs fell through to a plain string schema, and that was still the case after the 0.2.0 rewrite. A few things changed while landing it on top of 0.2.0:
Appreciate the contribution. |
futhr
added a commit
that referenced
this pull request
Jun 10, 2026
setup-beam resolves "28" to the latest patch build, and a PLT created on an older patch (28.5.0.1) fails with "Old PLT file" once a newer one (28.5.0.2) ships — exactly what broke the dialyzer job on PR #1. Keying on the resolved versions makes a toolchain bump rebuild the PLT instead of failing.
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.
when using typed structs inside an attribute it defaulted to string (see tests)
Summary by Sourcery
Relax embedded resource detection to support non-Ash.Resource types (e.g. typed structs) in attributes and extend the kitchen sink examples to cover discriminated union actors.
Enhancements:
Tests:
Greptile Summary
This PR fixes
Ash.TypedStructattributes silently degrading to"type": "string"in generated OpenAPI specs. The root cause was thatnormalize_newtype/1(formerly inlined) passed the resolved subtype (Ash.Type.Struct) throughnormalize_type/1, which had no mapping for it and fell through to:string.normalize_newtype/1which detectsAsh.Type.Structsubtypes and routes them to the newbuild_typed_struct_schema/1, which readssubtype_constraints()[:fields]to produce a typed object schema with accurate properties and arequiredlist.normalize_complex_type/1sojson_schema/1callbacks take priority over the embedded-resource check, aligning the priority with explicit user intent.Person,Company, andActortest fixtures and covers both the discriminated-union (anyOf) and direct-attribute (inline object) paths across OpenAPI 3.0 and 3.1, including Oaskit end-to-end validation.Confidence Score: 5/5
Safe to merge — the change is additive, covers a previously broken code path, and is validated end-to-end by Oaskit.
The core logic in
normalize_newtypeandbuild_typed_struct_schemais correct: it readssubtype_constraints()[:fields], maps declared field types through the existingash_type_to_base_schemapipeline, and sorts the required list. The priority reorder (json_schema callback before embedded check) is intentional and correct. No breaking changes to existing embedded-resource or union paths. The new Oaskit validation tests confirm the generated spec is structurally valid for both 3.0 and 3.1.No files require special attention beyond the documentation gaps noted in the comments.
Important Files Changed
normalize_newtype/1to routeAsh.Type.StructNewTypes to a newbuild_typed_struct_schema/1path; reorders embedded vs json_schema priority. Logic is sound, but lacks unit tests intype_mapper_test.exsand external doc updates (README, usage-rules).Person,CompanyTypedStruct modules and anActordiscriminated-union NewType; attaches them asactorandownerattributes on KitchenSink. Well-structured regression fixtures.Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A["normalize_complex_type(type)"] --> B{"has_json_schema_callback?"} B -- yes --> C["{:custom, json_schema}"] B -- no --> D{"embedded_resource?"} D -- yes --> E["{:embedded, type} → $ref"] D -- no --> F{"get_union_types?"} F -- yes --> G["{:union, types} → anyOf"] F -- no --> H{"enum_type?"} H -- yes --> I["{:custom, enum_schema}"] H -- no --> J{"newtype?"} J -- no --> K[":string fallback"] J -- yes --> L["normalize_newtype(type)"] L --> M{"subtype_of == Ash.Type.Struct?"} M -- yes --> N["{:struct_fields, type}"] N --> O["build_typed_struct_schema\nreads subtype_constraints()[:fields]\nproduces inline object schema"] M -- no --> P["normalize_type(subtype)\nrecurse on resolved subtype"] style N fill:#6bcb77,color:#000 style O fill:#6bcb77,color:#000 style L fill:#6bcb77,color:#000 style M fill:#6bcb77,color:#000Reviews (4): Last reviewed commit: "Merge branch 'main' into fix-typed-struc..." | Re-trigger Greptile
Context used: