DSL reference
v0.1.4
This page lists every option of the guardedstruct section and of the five entities you declare inside it: field, virtual_field, dynamic_field, sub_field and conditional_field. It describes GuardedStruct 0.1.4. For worked examples, start from Get started.
Section options
Pass these to guardedstruct, as in guardedstruct enforce: true, json: true do ... end.
| Option | Type | Default | Effect |
|---|---|---|---|
enforce | boolean | false | Requires every field that has no default. A field can opt out with enforce: false. It does not reach inside a sub_field. |
opaque | boolean | false | Generates @opaque t() instead of @type t(). |
module | module name | none | Generates the struct in a module nested under the current one. module: Struct inside MyApp.User generates MyApp.User.Struct, and a full name such as MyApp.User.Struct nests again as MyApp.User.MyApp.User.Struct. The outer module then has no builder. |
error | boolean | false | Generates the exception module <Module>.Error. |
authorized_fields | boolean | false | Turns every undeclared key of the input into an authorized_fields error. |
json | boolean | false | Derives a JSON encoder: Jason.Encoder if Jason is available, otherwise JSON.Encoder on Elixir 1.18 and later, otherwise nothing. Generated sub-modules get it too. |
main_validator | {Module, :function} | none | Called with the attributes after the field validators ran. A main_validator/1 defined in the module runs only when this option is not set. |
validate_derive | module or list of modules | none | Modules whose validate/3 serves the validate ops that no built-in op or derive extension handles. They are tried before the application config of the same name, which still serves the ops they leave unhandled. A sub_field uses them too. |
sanitize_derive | module or list of modules | none | Modules whose sanitize/2 serves the sanitize ops that no built-in op or derive extension handles. They are tried before the application config of the same name, which still serves the ops they leave unhandled. A sub_field uses them too. |
auto_wire | boolean | false | Only in an Ash resource: adds GuardedStruct.AshResource.Change to the resource. No effect elsewhere. |
Entities
| Entity | Signature | Use |
|---|---|---|
field | field name, type, opts | One value. With a regex as the name it describes a map with no fixed keys. |
virtual_field | virtual_field name, type, opts | A value that is checked and then left out of the struct. |
dynamic_field | dynamic_field name, opts | A map kept exactly as sent. The type defaults to map(), the default value to %{} and the derive string to validate(map). |
sub_field | sub_field name, type, opts do ... end | A struct declared inline, as its own module. |
conditional_field | conditional_field name, type, opts do ... end | One name with several possible shapes. |
A sub_field and a conditional_field hold field, sub_field and conditional_field entries. A sub_field also takes virtual_field and dynamic_field entries, and they behave as they do at the top level. The name of a sub_field and a conditional_field is an atom. The name of a field is an atom or a regex.
Options by entity
| Option | field | virtual_field | dynamic_field | sub_field | conditional_field |
|---|---|---|---|---|---|
enforce, default | Yes | Yes | Yes | Yes | Yes |
derives, derive | Yes | Yes | Yes | Yes | Yes |
validator | Yes | Yes | Yes | Yes | Yes |
auto, from, on, domain | Yes | Yes | Yes | Yes | Yes |
hint | Yes | Yes | Yes | Yes | Yes |
struct, structs | Yes | No | No | Yes | Yes |
priority | Yes | No | No | Yes | Yes |
error, authorized_fields, main_validator | No | No | No | Yes | No |
Option reference
| Option | Value | Effect |
|---|---|---|
name | atom, or regex for a field | The key. Declaring the same atom twice raises an ArgumentError. |
type | typespec | The type of the key in the generated @type t(). A key that is not enforced gets | nil added. |
enforce | boolean | Requires the key. A missing key is a required_fields error. On a sub_field it also requires the fields inside that have no default. |
default | value | The value in the struct when the key is absent. Maps and tuples are allowed. |
derives | string | The sanitize and validate ops. See Derive string syntax. |
derive | string | The old name of derives. It still works, and the compiler warns that it is deprecated. |
validator | {Module, :function} | Called as Module.function(field, value). See Write a field validator and a main validator. |
auto | {Module, :function} or {Module, :function, arg} | Fills the field by calling the function. A list as arg is spread as arguments. |
from | path string | Copies the value at the path into the field when that value is not nil. |
on | path string | When the field has a value, requires a value at the path, or a dependent_keys error follows. |
domain | rule string | Limits the field by values elsewhere in the input. See the next section. |
struct | module | Builds the value with Module.builder/1. |
structs | module or true | With a module, builds a list of values with Module.builder/1. With true on a sub_field or a conditional_field, the value is a list. |
hint | string | Copied as __hint__ into the errors of a child of a conditional_field. |
priority | boolean | On a conditional_field, keeps only the first error. A field and a sub_field accept it with no effect. |
error | boolean | On a sub_field, generates an Error exception module inside it. |
authorized_fields | boolean | On a sub_field, rejects undeclared keys inside it. |
main_validator | {Module, :function} | On a sub_field. Called with the attributes of that nested map after its field validators ran. A main_validator/1 of the parent module does not run for a sub_field. |
Path and rule strings
A from or on path is a list of keys joined with ::. A path that starts with root reads from the whole input. Any other path starts at the map of the struct being built.
A domain string is a list of rules joined with ::. Each rule is a prefix, a dotted path from the top of the input, =, and an operand.
!requires the path to exist.?allows it to be missing.- The operand is
String[...],Atom[...],Integer[...],Map[...],Tuple[...],Equal[...],Either[...]orCustom[Module, function]. Fill and check fields from other fields shows each one.
The derives decorator
In a module that uses use GuardedStruct, you can write a derive string as a module attribute above the entity it belongs to. The attribute applies to the next entity only, like @doc. @derive_rules is an alias. A derives: option on the entity wins over the attribute. An Ash resource does not read the attribute.
guardedstruct do
@derives "sanitize(trim) validate(string, not_empty, max_len=200)"
field :title, String.t(), enforce: true
@derives "validate(integer, min_len=0)"
field :views, integer(), default: 0
endFormatter
GuardedStruct exports locals_without_parens for its macros. Add it to your .formatter.exs so mix format leaves field :name, String.t() without parentheses.
[
import_deps: [:guarded_struct]
]