AshIntrospection.Rpc.FieldProcessing.Atomizer (AshIntrospection v0.3.0)

View Source

Handles preprocessing of requested fields, converting map keys to atoms while preserving field name strings for later reverse mapping lookup.

Field name strings are preserved so that downstream processors can perform proper reverse mapping lookups using the original client field names. The actual conversion to atoms happens in the field processor after the correct internal field name has been resolved.

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

Summary

Functions

Processes requested fields, converting map keys to atoms for navigation while preserving field name strings for reverse mapping.

Processes a single field, which can be a string, atom, or map structure.

Types

config()

@type config() :: %{
  optional(:input_field_formatter) => atom(),
  optional(:resource_info_module) => module(),
  optional(:is_interop_resource?) => (module() -> boolean()),
  optional(:get_original_field_name) => (module(), String.t() -> atom() | nil)
}

Functions

atomize_field(field, formatter, resource, config)

atomize_field_value(value, formatter, resource, config, atomize_strings)

atomize_requested_fields(requested_fields, resource \\ nil, config \\ %{})

@spec atomize_requested_fields(list(), module() | nil, config()) :: list()

Processes requested fields, converting map keys to atoms for navigation while preserving field name strings for reverse mapping.

For resources with field_names DSL mappings, those are applied to convert client names to internal names. For other types (TypedStructs, NewTypes), strings are preserved for the field processor to handle.

Parameters

  • requested_fields - List of strings/atoms or maps for relationships
  • resource - Optional resource module for field_names DSL lookup
  • config - Language-specific configuration with:
    • :input_field_formatter - The formatter for input field names (default: :camel_case)
    • :resource_info_module - Module implementing resource info callbacks (optional)
    • :is_interop_resource? - Function to check if resource is an interop resource
    • :get_original_field_name - Function to get original field name from client name

Examples

iex> atomize_requested_fields(["id", "title", %{"user" => ["id", "name"]}], nil, %{})
[:id, :title, %{user: ["id", "name"]}]

iex> atomize_requested_fields([%{"self" => %{"args" => %{"prefix" => "test"}}}], nil, %{})
[%{self: %{args: %{prefix: "test"}}}]

process_field(field, formatter, resource \\ nil, config \\ %{})

@spec process_field(term(), atom(), module() | nil, config()) :: term()

Processes a single field, which can be a string, atom, or map structure.

For string field names:

  • If resource has a field_names mapping for this client name, returns the mapped atom
  • Otherwise, preserves the string for downstream reverse mapping lookup

For map structures:

  • Converts map keys to atoms (for relationship/calculation navigation)
  • Preserves nested field name strings

process_field_value(value, formatter, resource \\ nil, config \\ %{}, atomize_strings \\ true)

@spec process_field_value(term(), atom(), module() | nil, config(), boolean()) ::
  term()

Processes field values, handling lists and nested maps.

For calculation args (maps with args/fields keys), converts all strings. For field selection lists, preserves strings for type-aware reverse mapping.