Exdantic.Wrapper (exdantic v0.0.2)
View SourceTemporary validation schemas for type coercion patterns.
This module supports the DSPy pattern of creating temporary, single-field
validation schemas for complex type coercion, equivalent to Pydantic's:
create_model("Wrapper", value=(target_type, ...))
Wrapper schemas are useful when you need to:
- Validate a single value against a complex type specification
- Apply field-level constraints and coercion
- Extract and unwrap validated values
- Perform temporary schema-based validation without defining a full schema
Summary
Functions
Creates a wrapper schema that can handle multiple input formats.
Creates multiple wrapper schemas for batch validation.
Creates a temporary wrapper schema for validating a single value.
Creates a reusable wrapper factory for a specific type and constraints.
Converts a wrapper schema back to its JSON Schema representation.
Unwraps a validated result, extracting just the field value.
Validates data using a wrapper schema and extracts the field value.
Validates data against a flexible wrapper that can handle multiple input formats.
Validates multiple values using their respective wrapper schemas.
Validates data using a wrapper schema and extracts the value in one step.
Gets metadata about a wrapper schema.
Checks if a schema is a wrapper schema created by this module.
Types
Functions
@spec create_flexible_wrapper( atom(), Exdantic.TypeAdapter.type_spec(), wrapper_options() ) :: wrapper_schema()
Creates a wrapper schema that can handle multiple input formats.
This wrapper can accept:
- The raw value directly
- A map with the field name as key
- A map with string keys
Parameters
field_name
- The field name for the wrappertype_spec
- The type specificationopts
- Wrapper options
Examples
iex> wrapper = Exdantic.Wrapper.create_flexible_wrapper(:age, :integer, coerce: true)
iex> Exdantic.Wrapper.validate_flexible(wrapper, 25, :age) # Raw value
{:ok, 25}
iex> Exdantic.Wrapper.validate_flexible(wrapper, %{age: 25}, :age) # Map with atom key
{:ok, 25}
iex> Exdantic.Wrapper.validate_flexible(wrapper, %{"age" => 25}, :age) # Map with string key
{:ok, 25}
@spec create_multiple_wrappers( [{atom(), Exdantic.TypeAdapter.type_spec(), wrapper_options()}], wrapper_options() ) :: %{required(atom()) => wrapper_schema()}
Creates multiple wrapper schemas for batch validation.
Parameters
field_specs
- List of {field_name, type_spec, opts} tuplesglobal_opts
- Options applied to all wrappers
Returns
- Map of field_name => wrapper_schema
Examples
iex> specs = [
...> {:name, :string, [constraints: [min_length: 1]]},
...> {:age, :integer, [constraints: [gt: 0]]},
...> {:email, :string, [constraints: [format: ~r/@/]]}
...> ]
iex> wrappers = Exdantic.Wrapper.create_multiple_wrappers(specs)
%{name: %DynamicSchema{...}, age: %DynamicSchema{...}, email: %DynamicSchema{...}}
@spec create_wrapper(atom(), Exdantic.TypeAdapter.type_spec(), wrapper_options()) :: wrapper_schema()
Creates a temporary wrapper schema for validating a single value.
Parameters
field_name
- The name for the wrapper field (atom)type_spec
- The type specification for the fieldopts
- Wrapper configuration options
Options
:required
- Whether the field is required (default: true):coerce
- Enable type coercion (default: false):constraints
- Additional field constraints (default: []):description
- Field description for documentation:example
- Example value for the field:default
- Default value if field is missing
Returns
- Wrapper schema that can be used for validation
Examples
iex> wrapper = Exdantic.Wrapper.create_wrapper(:result, :integer, coerce: true, constraints: [gt: 0])
%Exdantic.Runtime.DynamicSchema{...}
iex> wrapper = Exdantic.Wrapper.create_wrapper(:email, :string,
...> constraints: [format: ~r/@/], description: "Email address")
%Exdantic.Runtime.DynamicSchema{...}
@spec create_wrapper_factory(Exdantic.TypeAdapter.type_spec(), wrapper_options()) :: (atom() -> wrapper_schema())
Creates a reusable wrapper factory for a specific type and constraints.
Parameters
type_spec
- The type specification for the wrapperbase_opts
- Base options applied to all wrappers created by this factory
Returns
- Function that creates wrappers with the specified type and base options
Examples
iex> email_wrapper_factory = Exdantic.Wrapper.create_wrapper_factory(
...> :string,
...> constraints: [format: ~r/@/],
...> description: "Email address"
...> )
iex> user_email_wrapper = email_wrapper_factory.(:user_email)
iex> admin_email_wrapper = email_wrapper_factory.(:admin_email, required: false)
@spec to_json_schema( wrapper_schema(), keyword() ) :: map()
Converts a wrapper schema back to its JSON Schema representation.
Parameters
wrapper_schema
- The wrapper schema to convertopts
- JSON Schema generation options
Returns
- JSON Schema map representation of the wrapper
Examples
iex> wrapper = Exdantic.Wrapper.create_wrapper(:count, :integer, constraints: [gt: 0])
iex> Exdantic.Wrapper.to_json_schema(wrapper)
%{
"type" => "object",
"properties" => %{
"count" => %{"type" => "integer", "exclusiveMinimum" => 0}
},
"required" => ["count"]
}
Unwraps a validated result, extracting just the field value.
Utility function for extracting values from wrapper validation results.
Parameters
validated_result
- Result from wrapper validation (map)field_name
- The field name to extract
Returns
- The unwrapped field value
Examples
iex> validated = %{score: 85}
iex> Exdantic.Wrapper.unwrap_result(validated, :score)
85
@spec validate_and_extract(wrapper_schema(), term(), atom()) :: {:ok, term()} | {:error, [Exdantic.Error.t()]}
Validates data using a wrapper schema and extracts the field value.
Parameters
wrapper_schema
- The wrapper schema created by create_wrapper/3data
- The data to validate (can be the raw value or a map)field_name
- The field name to extract from the validated result
Returns
{:ok, extracted_value}
on successful validation and extraction{:error, errors}
on validation failure
Examples
iex> wrapper = Exdantic.Wrapper.create_wrapper(:count, :integer, coerce: true)
iex> Exdantic.Wrapper.validate_and_extract(wrapper, %{count: "42"}, :count)
{:ok, 42}
iex> Exdantic.Wrapper.validate_and_extract(wrapper, "42", :count) # Auto-wrap
{:ok, 42}
iex> Exdantic.Wrapper.validate_and_extract(wrapper, %{count: "abc"}, :count)
{:error, [%Exdantic.Error{...}]}
@spec validate_flexible(wrapper_schema(), term(), atom()) :: {:ok, term()} | {:error, [Exdantic.Error.t()]}
Validates data against a flexible wrapper that can handle multiple input formats.
Parameters
wrapper_schema
- The wrapper schemadata
- The input data (raw value, or map with atom/string keys)field_name
- The field name to extract
Returns
{:ok, validated_value}
on success{:error, errors}
on failure
@spec validate_multiple(%{required(atom()) => wrapper_schema()}, %{ required(atom()) => term() }) :: {:ok, %{required(atom()) => term()}} | {:error, %{required(atom()) => [Exdantic.Error.t()]}}
Validates multiple values using their respective wrapper schemas.
Parameters
wrappers
- Map of field_name => wrapper_schemadata
- Map of field_name => value to validate
Returns
{:ok, validated_values}
if all validations succeed{:error, errors_by_field}
if any validation fails
Examples
iex> wrappers = %{
...> name: Exdantic.Wrapper.create_wrapper(:name, :string),
...> age: Exdantic.Wrapper.create_wrapper(:age, :integer)
...> }
iex> data = %{name: "John", age: 30}
iex> Exdantic.Wrapper.validate_multiple(wrappers, data)
{:ok, %{name: "John", age: 30}}
@spec wrap_and_validate( atom(), Exdantic.TypeAdapter.type_spec(), term(), wrapper_options() ) :: {:ok, term()} | {:error, [Exdantic.Error.t()]}
Validates data using a wrapper schema and extracts the value in one step.
This is a convenience function that combines create_wrapper/3 and validate_and_extract/3.
Parameters
field_name
- The name for the wrapper fieldtype_spec
- The type specification for the fieldinput
- The data to validateopts
- Wrapper configuration options (same as create_wrapper/3)
Returns
{:ok, validated_value}
on successful validation{:error, errors}
on validation failure
Examples
iex> Exdantic.Wrapper.wrap_and_validate(:score, :integer, "85", coerce: true, constraints: [gteq: 0, lteq: 100])
{:ok, 85}
iex> Exdantic.Wrapper.wrap_and_validate(:email, :string, "invalid", constraints: [format: ~r/@/])
{:error, [%Exdantic.Error{...}]}
iex> Exdantic.Wrapper.wrap_and_validate(:items, {:array, :string}, ["a", "b", "c"])
{:ok, ["a", "b", "c"]}
@spec wrapper_info(wrapper_schema()) :: map()
Gets metadata about a wrapper schema.
Parameters
wrapper_schema
- The wrapper schema to inspect
Returns
- Map with wrapper metadata
Examples
iex> wrapper = Exdantic.Wrapper.create_wrapper(:email, :string, description: "User email")
iex> Exdantic.Wrapper.wrapper_info(wrapper)
%{
is_wrapper: true,
field_name: :email,
field_count: 1,
wrapper_type: :single_field,
created_at: ~U[...]
}
Checks if a schema is a wrapper schema created by this module.
Parameters
schema
- The schema to check
Returns
true
if it's a wrapper schema,false
otherwise
Examples
iex> wrapper = Exdantic.Wrapper.create_wrapper(:test, :string)
iex> Exdantic.Wrapper.wrapper_schema?(wrapper)
true
iex> regular_schema = Exdantic.Runtime.create_schema([{:name, :string}])
iex> Exdantic.Wrapper.wrapper_schema?(regular_schema)
false