An Elixir DSL for defining and validating structs.
defmodule ConstructorExampleUser do
use Constructor
constructor do
field :id, :integer, constructor: &is_integer/1, enforce: true
field :role, :user | :admin, constructor: &is_valid_role/1, enforce: true
field :first_name, :string, default: "", constructor: &is_string/1
field :last_name, :string, default: "", constructor: &is_string/1
end
def is_valid_role(value) do
case value do
:admin -> {:ok, value}
:user -> {:ok, value}
_ -> {:error, "invalid role!"}
end
end
end
iex> ConstructorExampleUser.new(id: "foo", role: :admin, first_name: 37)
{:error, {:constructor, %{id: "must be an integer", first_name: "must be an integer"}}}
iex> ConstructorExampleUser.new(id: 12, role: :admin, first_name: "Chris")
{:ok, %ConstructorExampleUser{id: 12, first_name: "Chris", last_name: ""}}
iex> ConstructorExampleUser.new!(id: 12, role: :admin, first_name: "Chris")
%ConstructorExampleUser{id: 12, first_name: "Chris", last_name: ""}
Check out the docs to learn more.
Add constructor
to your list of dependencies in mix.exs
:
def deps do
[
{:constructor, "~> 1.0"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/constructor.
Before writing the first iteration of this, I was using Vex
for projects that didn't have an Ecto dependency, or Ecto.Changeset
if I did.
It worked, but there were a couple of issues.
- Vex has some performance issues that seem difficult to resolve in a way that won't break existing users. More concerning, it seems like Vex is without a clear maintainer.
- You can do most of what
Constructor
does withEcto.Changesets
, but you bring a lot of ORM baggage along with it. Much of it may not be applicable if your project is not using an RDBMS.Constructor
provides a richer and more concise way of doing validations and type casting
This library was born from the lack of a lightweight and flexible validation library in Elixir.
However, the design of the constructor/2
macro and indeed much of the functionality
is provided by the excellent TypedStruct library.
If you already depend on TypedStruct, you will need to remove that dependency from your mix.exs until the plugin system is released. You can track progress here