GuardedStruct.Info (GuardedStruct v0.1.0-beta.1)

Copy Markdown View Source

Runtime introspection of guardedstruct DSL state.

Built on Spark.InfoGenerator, which auto-generates accessors for every section option in the DSL (e.g. guardedstruct_enforce!/1, guardedstruct_json!/1). On top of those, this module exposes ergonomic helpers so callers don't have to walk __fields__/0 maps themselves.

Helper categories

Example

defmodule MyApp.User do
  use GuardedStruct
  guardedstruct enforce: true do
    field :name, String.t()
    virtual_field :password_confirm, String.t()
    sub_field :address, struct() do
      field :city, String.t()
    end
  end
end

GuardedStruct.Info.fields(MyApp.User)            #=> [:name, :password_confirm, :address]
GuardedStruct.Info.virtual_fields(MyApp.User)    #=> [:password_confirm]
GuardedStruct.Info.sub_fields(MyApp.User)        #=> [:address]
GuardedStruct.Info.field_kind(MyApp.User, :name) #=> :field
GuardedStruct.Info.enforce?(MyApp.User, :name)   #=> true
GuardedStruct.Info.sub_module(MyApp.User, :address) #=> MyApp.User.Address

Summary

Functions

True if the section was declared with authorized_fields: true.

Return the children variants of a conditional_field, or nil if the name isn't a conditional. Each child is a meta map with :kind, :name, and any associated options.

Names of all conditional_field entries on this module.

Names of conditionalfield entries, sourced from `_information/0's:conditional_keys(matchesconditional_fields/1` for normal modules).

Return the FULL introspection map for a module: every section option, every field's complete metadata, every derived flag, in one structure.

True if name is a dynamic_field.

Names of all dynamic_field entries on this module.

True if the section was declared with enforce: true.

True if the field is enforced (member of enforce_keys/0).

Return the list of enforced field names.

True if the section was declared with error: true.

Return the field metadata for a single name, or nil if absent.

True if the field exists on this module (or any sub_field cascade).

Return the {Mod, fun} auto: MFA, or nil if none.

Return the field's default:, or nil if none or field absent.

Return the original derive string for a field (the canonical derives: option, falling back to the legacy derive:).

Return the kind of a field: :field, :sub_field, :virtual_field, :dynamic_field, :conditional_field, or :pattern_field. nil if the field doesn't exist.

Return the {Mod, fun} per-field validator MFA, or nil if none.

Return the user-declared field, sub_field, virtual_field, dynamic_field and conditional_field names in declaration order. Works on both the top-level module and any generated sub_field submodule.

Return the runtime field metadata — same shape as the generated module's __fields__/0.

guardedstruct DSL entities

Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.

Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.

When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.

When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.

guardedstruct DSL options

True if the section was declared with json: true.

True if the section was declared with opaque: true.

True if this module was generated for a pattern-keyed map (its only field was a regex). Pattern-keyed modules return a map from builder/1, not a struct.

Names of all sub_field entries on this module.

Return the generated submodule for a sub_field, or nil if the name isn't a sub_field. The submodule path is the parent module concatenated with the camelized field name (or with the section's module: override).

True if name is a virtual_field.

Names of all virtual_field entries on this module.

Functions

authorized_fields?(module)

True if the section was declared with authorized_fields: true.

conditional_children(module, name)

Return the children variants of a conditional_field, or nil if the name isn't a conditional. Each child is a meta map with :kind, :name, and any associated options.

conditional_fields(module)

Names of all conditional_field entries on this module.

conditional_keys(module)

Names of conditionalfield entries, sourced from `_information/0's:conditional_keys(matchesconditional_fields/1` for normal modules).

describe(module)

Return the FULL introspection map for a module: every section option, every field's complete metadata, every derived flag, in one structure.

Works on both the top-level module and any generated sub_field submodule. Section-option keys whose values were not declared are present as nil, so the shape is uniform.

Returned map keys

  • :module — the module
  • :path — module path from root (empty list for the top-level)
  • :key — the field name corresponding to this module (or :root)
  • :shape:struct or :pattern_map
  • :pattern_keyed? — convenience boolean
  • :patterns — for pattern-map shapes, the list of regex field names
  • :keys — struct-bound key names (excludes virtuals)
  • :enforce_keys — names of enforced keys
  • :conditional_keys — names of conditional_field entries
  • :options — map of every section option (with nil for absent values)
  • :fields — list of per-field meta maps (one per declared entity), each augmented with :enforce? (membership in enforce_keys) and, for sub_field entries, :sub_module (the generated submodule)

Example

Info.describe(MyApp.User)
#=> %{
#     module: MyApp.User,
#     path: [],
#     key: :root,
#     shape: :struct,
#     pattern_keyed?: false,
#     patterns: [],
#     keys: [:id, :name, :address, ...],
#     enforce_keys: [:name, :address],
#     conditional_keys: [:billing],
#     options: %{
#       enforce: true, opaque: false, module: nil, error: false,
#       authorized_fields: true, main_validator: nil,
#       validate_derive: nil, sanitize_derive: nil, json: true
#     },
#     fields: [
#       %{name: :id, kind: :field, enforce?: false, ...},
#       %{name: :address, kind: :sub_field, enforce?: true,
#         sub_module: MyApp.User.Address, ...},
#       ...
#     ]
#   }

dynamic?(module, name)

True if name is a dynamic_field.

dynamic_fields(module)

Names of all dynamic_field entries on this module.

enforce?(module)

True if the section was declared with enforce: true.

enforce?(module, name)

True if the field is enforced (member of enforce_keys/0).

enforce_keys(module)

Return the list of enforced field names.

error?(module)

True if the section was declared with error: true.

field(module, name)

Return the field metadata for a single name, or nil if absent.

field?(module, name)

True if the field exists on this module (or any sub_field cascade).

field_auto(module, name)

Return the {Mod, fun} auto: MFA, or nil if none.

field_default(module, name)

Return the field's default:, or nil if none or field absent.

field_derives(module, name)

Return the original derive string for a field (the canonical derives: option, falling back to the legacy derive:).

field_kind(module, name)

Return the kind of a field: :field, :sub_field, :virtual_field, :dynamic_field, :conditional_field, or :pattern_field. nil if the field doesn't exist.

field_validator(module, name)

Return the {Mod, fun} per-field validator MFA, or nil if none.

fields(module)

Return the user-declared field, sub_field, virtual_field, dynamic_field and conditional_field names in declaration order. Works on both the top-level module and any generated sub_field submodule.

fields_meta(module)

Return the runtime field metadata — same shape as the generated module's __fields__/0.

guardedstruct(dsl_or_extended)

@spec guardedstruct(dsl_or_extended :: module() | map()) :: [struct()]

guardedstruct DSL entities

guardedstruct_auto_wire(dsl_or_extended)

@spec guardedstruct_auto_wire(dsl_or_extended :: module() | map()) ::
  {:ok, boolean()} | :error

Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.

guardedstruct_auto_wire!(dsl_or_extended)

@spec guardedstruct_auto_wire!(dsl_or_extended :: module() | map()) ::
  boolean() | no_return()

Only effective inside the GuardedStruct.AshResource extension. When true, injects GuardedStruct.AshResource.Change into the resource's top-level changes section so every :create and :update action automatically runs the GuardedStruct pipeline. Equivalent to writing changes do change GuardedStruct.AshResource.Change end by hand. No-op outside the Ash extension.

guardedstruct_json(dsl_or_extended)

@spec guardedstruct_json(dsl_or_extended :: module() | map()) ::
  {:ok, boolean()} | :error

When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.

guardedstruct_json!(dsl_or_extended)

@spec guardedstruct_json!(dsl_or_extended :: module() | map()) ::
  boolean() | no_return()

When true, derives a JSON encoder. Uses Jason.Encoder if :jason is in the user's deps; otherwise falls back to the built-in JSON.Encoder on Elixir 1.18+. No-op if neither is available.

guardedstruct_options(dsl_or_extended)

@spec guardedstruct_options(dsl_or_extended :: module() | map()) :: %{
  required(atom()) => any()
}

guardedstruct DSL options

Returns a map containing the and any configured or default values.

json?(module)

True if the section was declared with json: true.

opaque?(module)

True if the section was declared with opaque: true.

pattern_keyed?(module)

True if this module was generated for a pattern-keyed map (its only field was a regex). Pattern-keyed modules return a map from builder/1, not a struct.

sub_fields(module)

Names of all sub_field entries on this module.

sub_module(module, name)

Return the generated submodule for a sub_field, or nil if the name isn't a sub_field. The submodule path is the parent module concatenated with the camelized field name (or with the section's module: override).

Info.sub_module(MyApp.User, :address)
#=> MyApp.User.Address

virtual?(module, name)

True if name is a virtual_field.

virtual_fields(module)

Names of all virtual_field entries on this module.