Turns a projected GraphQL selection set into an exact Repo.preload/2 tree.
Given a recursively normalized list of Absinthe.Blueprint.Document.Field
nodes and the root Ecto schema of the field, the engine keeps only the fields
that name a real association of the current schema — asking
AbsintheProjector.Introspection, never a whitelist — recurses into each match
using the association's related schema, and merges duplicate or aliased
requests of the same association by unioning their child selections.
Association matching keys on schema_node.identifier (the schema field atom),
so GraphQL aliases and repeated fields collapse to a single entry. Scalar
fields, __typename, introspection nodes (schema_node == nil) and any
identifier that is not an association are skipped silently. An association
whose sub-selection contains no further associations is emitted as a bare atom
(a leaf); otherwise it becomes a {association, children} keyword entry.
The function is pure — no process state, no database access — and looks up a schema's associations once per recursion level.
Examples
Flat selection (scalars dropped, association-less children collapse to a leaf):
# order { number status customer { name } }
project(fields, Order) #=> [:customer]Nested selection:
# order { customer { name } items { product { supplier { name } } } }
project(fields, Order) #=> [:customer, items: [product: [:supplier]]]Aliased duplicates merge into one entry with the union of their children:
# a: items { product } b: items { }
project(fields, Order) #=> [items: [:product]]A selection with no associations yields an empty, no-op tree:
# order { number status }
project(fields, Order) #=> []
Summary
Functions
Projects fields against schema, returning the nested Repo.preload/2 tree.
Functions
@spec project([struct()], module()) :: AbsintheProjector.preload_tree()
Projects fields against schema, returning the nested Repo.preload/2 tree.
fields is a list of Absinthe.Blueprint.Document.Field nodes; schema is
the root Ecto schema module. Returns [] when the selection contains no
associations. Raises ArgumentError (via Introspection) when schema is not
an Ecto schema module.