AshIntrospection.Rpc.FieldProcessing.FieldSelector (AshIntrospection v0.4.0)

Copy Markdown View Source

Unified field selection processor using type-driven recursive dispatch.

This module mirrors the architecture of ValueFormatter, using the same {type, constraints} pattern for type-driven dispatch. Each type is self-describing - no separate classification step is needed.

This is a shared module used by both AshTypescript and AshKotlinMultiplatform. Language-specific behavior is configured via the config parameter.

Design Principle

The key insight is that field selection and value formatting are parallel operations - both traverse composite types recursively based on type information. By using the same dispatch pattern, we achieve consistency and simplicity.

Type Categories

CategoryDetectionHandler
Ash ResourceResourceInfo.runtime_resource?(type, config)select_resource_fields/4
TypedStruct/NewTypefield_names callbackselect_typed_struct_fields/4
Typed Map/StructHas fields constraintsselect_typed_map_fields/5
TupleAsh.Type.Tupleselect_tuple_fields/4
UnionAsh.Type.Unionselect_union_fields/5
Array{:array, inner_type}Recurse with inner type
PrimitiveDefaultValidate no fields requested

Summary

Functions

Converts an action to its type specification.

Processes requested fields for a given resource and action.

Main recursive dispatch function for field selection.

Selects fields from a tuple type using named fields.

Selects fields from a typed map (Ash.Type.Map/Keyword with field constraints).

Selects fields from a TypedStruct or NewType with field_names callback.

Types

config()

@type config() :: %{
  optional(:input_field_formatter) => atom(),
  optional(:field_names_callback) => atom(),
  optional(:resource_info_module) => module(),
  optional(:is_interop_resource?) => (module() -> boolean()),
  optional(:get_original_field_name) => (module(), term() -> atom() | nil),
  optional(:load_restrictions) => term(),
  optional(:manifest) =>
    Ash.Info.Manifest.t() | AshIntrospection.ResourceInfo.Source.t() | nil
}

select_result()

@type select_result() :: {select :: [atom()], load :: [term()], template :: [term()]}

Functions

action_to_type_spec(resource, action)

@spec action_to_type_spec(module(), Ash.Resource.Actions.action()) ::
  {atom() | tuple(), keyword()}

Converts an action to its type specification.

Returns {type, constraints} tuple representing the action's return type.

process(resource, action_name, requested_fields, config \\ %{})

@spec process(module(), atom(), list(), config()) ::
  {:ok, select_result()} | {:error, term()}

Processes requested fields for a given resource and action.

Returns {:ok, {select_fields, load_fields, extraction_template}} or {:error, error}.

Parameters

  • resource - The Ash resource module
  • action_name - The action name (atom)
  • requested_fields - List of field selections (atoms, strings, or maps)
  • config - Language-specific configuration. An optional :load_restrictions key shapes which relationships, calculations and aggregates the caller may ask for - see AshIntrospection.Rpc.LoadRestrictions. Omitting it permits every load.

Examples

iex> process(MyApp.Todo, :read, [:id, :title, %{user: [:id, :name]}], %{})
{:ok, {[:id, :title], [{:user, [:id, :name]}], [:id, :title, {:user, [:id, :name]}]}}

select_fields(type, constraints, requested_fields, path, config)

@spec select_fields(atom() | tuple(), keyword(), list(), list(), config()) ::
  select_result()

Main recursive dispatch function for field selection.

Mirrors ValueFormatter.format/5 - uses the same type detection and dispatch pattern. Each type category has its own handler that may recurse back into this function.

select_resource_fields(resource, requested_fields, path, config)

Selects fields from an Ash resource.

Handles attributes, calculations, relationships, and aggregates.

select_tuple_fields(constraints, requested_fields, path, config)

Selects fields from a tuple type using named fields.

select_typed_map_fields(constraints, requested_fields, path, config, error_type \\ "field_constrained_type")

Selects fields from a typed map (Ash.Type.Map/Keyword with field constraints).

select_typed_struct_fields(constraints, requested_fields, path, config)

Selects fields from a TypedStruct or NewType with field_names callback.

select_union_fields(constraints, requested_fields, path, config, error_type \\ "union_type")

Selects fields from a union type.