Generates EctoTypedSchema embedded schema modules from GraphQL query AST.
Given an operation definition and a schema, generates per-query output type modules with proper nesting, nullability, and field alias support.
Generation pipeline
Generation runs as four named steps:
normalize— raw selections to canonical selections: expands fragment spreads, flattens inline fragments on object types, and propagates ancestor (inline-fragment / fragment-spread) directives down onto each field'sdirectives.resolve— canonical selections + schema to aTypedGql.Generation.Schematree. The whole tree is built before any lowering.lower— tree to{module, quoted_ast}pairs.create—{module, ast}pairs to BEAM modules.
TypedGql.Generation.Plugin documents which steps a plugin may hook and in
what order the built-in and user plugins run.
Naming convention
Output types follow per-query path naming under a Result namespace:
ClientModule.FunctionName.Result.FieldName.NestedField...Field aliases override both struct field names and module path segments.
Lists of objects
Only [T!]! becomes embeds_many: Ecto loads a null many-embed as [] and
raises on a null element, so that is the one shape it models faithfully.
Every other list of a composite — [T], [T]!, [T!], and any nesting such
as [[T]] — becomes a plain field over the parameterized Ecto.Embedded
type with cardinality: :one, which loads nil as nil at every level.
A [T!]! carrying @skip/@include is a plain field too: the response can
omit it entirely, and embeds_many pins default: [], which would report a
list the server never sent as an empty one.
A list the schema declares non-null — [T!]! and [T]! alike — defaults to
[] rather than nil, since its typespec carries no | nil. Only a
conditional one keeps a nil default, for the same reason it loses
embeds_many.
Union/Interface support
When a field's type is a union or interface, inline fragments determine
which concrete types to generate. Shared fields (outside fragments) are
merged into each concrete type's struct. A parameterized TypedGql.Types.Union
Ecto Type handles __typename-based dispatch during deserialization.
Summary
Functions
Generates embedded schema modules for an operation's output types.
Generates the result modules for a named fragment under
ClientModule.Fragments.FragmentName.
Types
@type option() :: {:client_module, module()} | {:function_name, atom()} | {:scalar_types, map()} | {:fragments, %{required(String.t()) => TypedGql.Language.Fragment.t()}} | {:generation_plugins, [module()]} | {:caller_env, Macro.Env.t()}
Functions
@spec generate(TypedGql.Language.OperationDefinition.t(), TypedGql.Schema.t(), [ option() ]) :: [module()]
Generates embedded schema modules for an operation's output types.
Returns a list of generated module names.
Options
:client_module— the parent client module (e.g.,MyApp.UserService):function_name— the defgql function name (e.g.,:get_user):scalar_types— custom scalar type mappings (default:%{}):fragments—TypedGql.Language.Fragmentdefinitions by name, for spread expansion; a spread naming one that is absent raisesCompileError(default:%{}):generation_plugins— userTypedGql.Generation.Pluginmodules, appended after the built-in plugins (default:[]):caller_env— the macro caller'sMacro.Env, used to set generated modules' source location for editor "go to definition" support
@spec generate_fragment( TypedGql.Language.Fragment.t(), TypedGql.Schema.t(), module(), [option()] ) :: module()
Generates the result modules for a named fragment under
ClientModule.Fragments.FragmentName.
Takes the same options as generate/3 except :client_module and
:function_name, which the fragment's own name replaces.
This was generate_fragment/5 up to 0.12.2, taking scalar_types as a bare
fourth argument and the plugin list as a fifth. Both are options now, so a
caller passing scalar_types positionally has to wrap it:
generate_fragment(fragment, schema, client_module, scalar_types: types).
Returns the module that stands for the fragment's result. For an object
type condition — and for an abstract one whose selections every member
shares — that is the embedded schema at Fragments.FragmentName. For a
condition with per-member selections there is no single struct: the return
is the TypedGql.Types.Union parameterized type at
Fragments.FragmentName.Union, which dispatches on __typename to the
per-member embedded schemas at Fragments.FragmentName.MemberType.