AbsintheProjector.Envelope (AbsintheProjector v0.1.1)

Copy Markdown View Source

Walks a projected GraphQL selection down a pagination-envelope key path, returning the innermost selection that AbsintheProjector.Engine should project against the declared :schema.

A Flop-style list query wraps the real entities inside a data field (data { … } meta { … }); custom wrappers may nest deeper (page { entries { … } }). The envelope option on the middleware names that wrapper as a key path — a single atom (:data) or a list of atoms ([:page, :entries]) — and this module descends it before projection so only the entity selection reaches the engine.

The descent is deliberately schema-agnostic: at each level it matches the key against schema_node.identifier (the same structural matching the engine uses), never against an Ecto association, so wrapper types (data/meta, page/entries) need no schema. The sub-selections of every field whose identifier matches the key are unioned (order of appearance), so aliased or duplicated envelope wrappers collapse the same way the engine dedups associations.

An empty path is the no-envelope identity — the selection is returned unchanged, so a field without the envelope option projects from its root exactly like a single-record field. When a key matches no field at some level, the descent returns [], so a meta-only list query (only meta { total } requested) yields an empty preload tree and downstream Repo.preload/2 stays a safe no-op.

The function is pure — no schema lookup, no database access, no process state.

Examples

Single-level Flop envelope (only data's selection survives):

# data { customer { name } } meta { total }
descend(fields, [:data]) #=> [ %Field{schema_node: %{identifier: :customer}, …} ]

Multi-level envelope descends every level in order:

# page { entries { customer } }
descend(fields, [:page, :entries]) #=> [ %Field{… :customer …} ]

Missing envelope field yields an empty selection:

# meta { total }   (no `data`)
descend(fields, [:data]) #=> []

Empty path is the no-envelope identity:

descend(fields, []) #=> fields

Summary

Functions

Descends fields down the normalized key path, returning the innermost selection.

Functions

descend(fields, path)

@spec descend([struct()], [atom()]) :: [struct()]

Descends fields down the normalized key path, returning the innermost selection.

With an empty path, returns fields unchanged (the no-envelope identity). Otherwise, for each key in order, keeps the unioned .selections of every field whose schema_node.identifier matches the key; returns [] as soon as a key matches no field.