Exdantic.Types (exdantic v0.0.2)
View SourceCore type system for Exdantic schemas.
Provides functions for defining and working with types:
- Basic types (:string, :integer, :float, :boolean)
- Complex types (arrays, maps, unions)
- Type constraints
- Type validation
- Type coercion
Basic Types
# String type
Types.string()
# Integer type with constraints
Types.integer()
|> Types.with_constraints(gt: 0, lt: 100)
Complex Types
# Array of strings
Types.array(Types.string())
# Map with string keys and integer values
Types.map(Types.string(), Types.integer())
# Union of types
Types.union([Types.string(), Types.integer()])
Type Constraints
Constraints can be added to types to enforce additional rules:
Types.string()
|> Types.with_constraints([
min_length: 3,
max_length: 10,
format: ~r/^[a-z]+$/
])
Summary
Functions
Coerces a value to the specified type.
Normalizes a type definition to the standard internal format.
Validates a value against a basic type.
Adds constraints to a type definition.
Adds a custom error message for a specific constraint to a type definition.
Adds multiple custom error messages for constraints to a type definition.
Adds a custom validation function to a type definition.
Types
@type type_definition() :: {:type, atom(), [any()]} | {:array, type_definition(), [any()]} | {:map, {type_definition(), type_definition()}, [any()]} | {:object, %{required(atom()) => type_definition()}, [any()]} | {:union, [type_definition()], [any()]} | {:ref, atom()}
Functions
@spec array(type_definition()) :: {:array, type_definition(), []}
@spec boolean() :: {:type, :boolean, []}
Coerces a value to the specified type.
Parameters
type
- The target type to coerce tovalue
- The value to coerce
Returns
{:ok, coerced_value}
on success{:error, reason}
on failure
Examples
iex> Exdantic.Types.coerce(:string, 42)
{:ok, "42"}
iex> Exdantic.Types.coerce(:integer, "123")
{:ok, 123}
iex> Exdantic.Types.coerce(:integer, "abc")
{:error, "invalid integer format"}
@spec float() :: {:type, :float, []}
@spec integer() :: {:type, :integer, []}
@spec map(type_definition(), type_definition()) :: {:map, {type_definition(), type_definition()}, []}
@spec normalize_type(term()) :: type_definition()
Normalizes a type definition to the standard internal format.
Parameters
type
- The type definition to normalize
Returns
- A normalized type definition tuple
Examples
iex> Exdantic.Types.normalize_type(:string)
{:type, :string, []}
iex> Exdantic.Types.normalize_type({:array, :integer})
{:array, {:type, :integer, []}, []}
@spec object(%{required(atom()) => type_definition()}) :: {:object, %{required(atom()) => type_definition()}, []}
@spec string() :: {:type, :string, []}
@spec tuple([type_definition()]) :: {:tuple, [type_definition()]}
@spec union([type_definition()]) :: {:union, [type_definition()], []}
@spec validate(atom(), term()) :: {:ok, term()} | {:error, Exdantic.Error.t()}
Validates a value against a basic type.
Parameters
type
- The type to validate againstvalue
- The value to validate
Returns
{:ok, value}
if validation succeeds{:error, Exdantic.Error.t()}
if validation fails
Examples
iex> Exdantic.Types.validate(:string, "hello")
{:ok, "hello"}
iex> Exdantic.Types.validate(:integer, "not a number")
{:error, %Exdantic.Error{path: [], code: :type, message: "expected integer, got "not a number""}}
@spec with_constraints(type_definition(), [term()]) :: {atom(), term(), [term()]}
Adds constraints to a type definition.
Parameters
type
- The type definition to add constraints toconstraints
- List of constraints to add
Returns
- Updated type definition with constraints
Examples
iex> string_type = Exdantic.Types.string()
iex> Exdantic.Types.with_constraints(string_type, [min_length: 3, max_length: 10])
{:type, :string, [min_length: 3, max_length: 10]}
Adds a custom error message for a specific constraint to a type definition.
Parameters
type
- The type definition to add the custom error message toconstraint
- The constraint name (atom) to customize the error formessage
- The custom error message to use when this constraint fails
Returns
- Updated type definition with custom error message
Examples
iex> string_type = Exdantic.Types.string()
iex> |> Exdantic.Types.with_constraints([min_length: 3])
iex> |> Exdantic.Types.with_error_message(:min_length, "Name must be at least 3 characters long")
{:type, :string, [min_length: 3, {:error_message, :min_length, "Name must be at least 3 characters long"}]}
@spec with_error_messages( type_definition(), [{atom(), String.t()}] | %{required(atom()) => String.t()} ) :: {atom(), term(), [term()]}
Adds multiple custom error messages for constraints to a type definition.
Parameters
type
- The type definition to add the custom error messages toerror_messages
- A keyword list or map of constraint => message pairs
Returns
- Updated type definition with custom error messages
Examples
iex> string_type = Exdantic.Types.string()
iex> |> Exdantic.Types.with_constraints([min_length: 3, max_length: 50])
iex> |> Exdantic.Types.with_error_messages([
iex> min_length: "Name must be at least 3 characters long",
iex> max_length: "Name cannot exceed 50 characters"
iex> ])
{:type, :string, [min_length: 3, max_length: 50, {:error_message, :min_length, "Name must be at least 3 characters long"}, {:error_message, :max_length, "Name cannot exceed 50 characters"}]}
@spec with_validator(type_definition(), (term() -> {:ok, term()} | {:error, String.t()})) :: {atom(), term(), [term()]}
Adds a custom validation function to a type definition.
Parameters
type
- The type definition to add the custom validator tovalidator_fn
- A function that takes a value and returns {:ok, value} | {:error, message}
Returns
- Updated type definition with custom validator
Examples
iex> email_type = Exdantic.Types.string()
iex> |> Exdantic.Types.with_constraints([min_length: 3])
iex> |> Exdantic.Types.with_validator(fn value ->
iex> if String.contains?(value, "@"), do: {:ok, value}, else: {:error, "Must contain @"}
iex> end)
{:type, :string, [min_length: 3, {:validator, #Function<...>}]}