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.

Search Document