mochi/selection
Reading what the client selected, so a resolver can fetch only what was
asked for instead of select *.
Everything here is a plain function over List(SelectedField). Get the list
once with schema.selection(ctx), then pipe:
resolve: fn(args, ctx) {
let selected = schema.selection(ctx)
selected |> selection.columns(always: ["id"]) // ["first_name", "id"]
selected |> selection.has("posts") // worth a join?
selected |> selection.children("posts") // the nested selection
selected |> selection.for_type("Cat") // narrow a union
...
}
Binding the list once matters: schema.selection recomputes on each call.
Values
pub fn applies_to(
field: schema.SelectedField,
type_name: String,
) -> Bool
Whether one selected field applies to a resolver returning type_name.
pub fn argument(
field: schema.SelectedField,
name: String,
) -> option.Option(dynamic.Dynamic)
An argument written on a selected field, with variables substituted.
Raw literal shape: not coerced against the schema, so schema defaults are
absent and enum values arrive as strings. Coerced arguments come from the
resolver’s own Args.
pub fn bool_argument(
field: schema.SelectedField,
name: String,
) -> option.Option(Bool)
A Bool argument.
pub fn children(
fields: List(schema.SelectedField),
name: String,
) -> List(schema.SelectedField)
The sub-selection under name, pooled across every entry for it. Empty when
name was not selected, or is a leaf.
pub fn columns(
fields: List(schema.SelectedField),
always always: List(String),
) -> List(String)
The storage columns the selection needs, as declared in the schema with
types.from_columns / types.no_columns.
always is appended unconditionally: put the primary key and any foreign key
a nested resolver needs there, otherwise a query selecting only computed
fields comes back with no key to join on.
pub fn find(
fields: List(schema.SelectedField),
name: String,
) -> List(schema.SelectedField)
Every entry for name — one per distinct type condition and argument set.
// { posts(first: 1) { id } recent: posts(first: 5) { title } }
selected |> selection.find("posts") // two entries
pub fn for_type(
fields: List(schema.SelectedField),
type_name: String,
) -> List(schema.SelectedField)
The selection narrowed to what applies when the resolver returns type_name:
unconditional fields plus those from fragments whose type condition covers it.
An empty result means nobody asked about that type, so its table need not be queried at all.
pub fn has(
fields: List(schema.SelectedField),
name: String,
) -> Bool
Whether name was selected.
pub fn int_argument(
field: schema.SelectedField,
name: String,
) -> option.Option(Int)
An Int argument, e.g. a nested first: 10 to honour when prefetching.
pub fn names(fields: List(schema.SelectedField)) -> List(String)
The selected field names, deduplicated, in the order they were selected.
pub fn string_argument(
field: schema.SelectedField,
name: String,
) -> option.Option(String)
A String argument.