EctoTaggedUnion
TODO: Add description
Installation
If available in Hex, the package can be installed
by adding ecto_tagged_union
to your list of dependencies in mix.exs
:
def deps do
[
{:ecto_tagged_union, "~> 0.1.0"}
]
end
Usage
First, define variant schemas:
defmodule Shape.Circle do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
embedded_schema do
field :radius, :integer
end
@fields [:radius]
def changeset(data, attrs) do
data
|> cast(attrs, @fields)
end
end
defmodule Shape.Rectangle do
use Ecto.Schema
import Ecto.Changeset
@primary_key false
embedded_schema do
field :height, :integer
field :width, :integer
end
@fields [:height, :width]
def changeset(data, attrs) do
data
|> cast(attrs, @fields)
end
end
Internally tagged
By default, tag is stored next to other fields of the variant.
defmodule Shape do
import EctoTaggedUnion
alias Shape.Circle
alias Shape.Rectangle
defunion Circle | Rectangle
end
iex> Shape.dump(%Shape.Circle{radius: 10})
%{radius: 10, tag: "Circle"}
iex> Shape.load(%{"radius" => 10, "tag" => "Circle"})
%Shape.Circle{radius: 10}
iex> Shape.cast(%{radius: 10, tag: "Circle"})
%Shape.Circle{radius: 10}
Externally tagged
defmodule Shape do
import EctoTaggedUnion
alias Shape.Circle
alias Shape.Rectangle
defunion Circle | Rectangle, :external
end
iex> Shape.dump(%Shape.Circle{radius: 10})
%{"Circle" => %{radius: 10}}
iex> Shape.load(%{"Circle" => %{"radius" => 10}})
%Shape.Circle{radius: 10}
iex> Shape.cast(%{"Circle" => %{radius: 10}})
%Shape.Circle{radius: 10}
Adjacently tagged
The tag and the content are adjacent to each other as two fields within the same map.
defmodule Shape do
import EctoTaggedUnion
alias Shape.Circle
alias Shape.Rectangle
defunion Circle | Rectangle, :adjacent, tag: :t, content: :c
end
iex> Shape.dump(%Shape.Circle{radius: 10})
%{c: %{radius: 10}, t: "Circle"}
iex> Shape.load(%{"c" => %{"radius" => 10}, "t" => "Circle"})
%Shape.Circle{radius: 10}
iex> Shape.cast(%{t: "Circle", c: %{radius: 10}})
%Shape.Circle{radius: 10}