ecto_diff v0.2.0 EctoDiff View Source
Generates a data structure describing the difference between two ecto structs.
For details on how to generate an EctoDiff.t/0
struct, see: diff/2
.
For details on what the generated struct looks like, see: EctoDiff.t/0
.
Link to this section Summary
Types
The type of change for a given struct.
Describes all changes made during an insert or update operation.
Functions
Returns an EctoDiff.t/0
describing the difference between two given ecto structs.
Link to this section Types
effect()
View Source
effect() :: :added | :deleted | :changed | :replaced
effect() :: :added | :deleted | :changed | :replaced
The type of change for a given struct.
Each EctoDiff.t/0
struct will have a field describing what happened to the given ecto struct. The values can be one of
the following:
:added
- This struct is new and was not present previously. This happens when the primary struct, or an associated struct, was added during an update or insert.:deleted
- This struct was previously present, but no longer is.:changed
- This struct existed previously and still does, but some of its fields and/or associations have changed.:replaced
- This struct was replaced with a completely new one. This happens withbelongs_to
orembeds_one
associations with theon_replace: :nilify
option set.
t()
View Source
t() :: %EctoDiff{
changes: %{required(atom()) => any()},
current: Ecto.Schema.t(),
effect: effect(),
previous: Ecto.Schema.t(),
primary_key: %{required(atom()) => any()},
struct: atom()
}
t() :: %EctoDiff{ changes: %{required(atom()) => any()}, current: Ecto.Schema.t(), effect: effect(), previous: Ecto.Schema.t(), primary_key: %{required(atom()) => any()}, struct: atom() }
Describes all changes made during an insert or update operation.
The following fields should be considered public:
struct
- The module atom of the ecto schema being diffed.primary_key
- The primary key(s) of the ecto struct. This is amap
of all primary keys in case of composite keys. For most common use-cases this will just be the map%{id: id}
.changed
- Amap
representing all changes made. The keys will be fields and associations defined in the ecto schema, but only fields and associations with changes will be present. For changed fields, the value will be atuple
representing the previous and new values (i.e.{previous, new}
). For associations, the value will be anotherEctoDiff.t/0
struct for cardinality "one" associations, or a list ofEctoDiff.t/0
structs for cardinality "many" associations.effect
- The type of change for this ecto struct. Seeeffect/0
for details.previous
- The previous struct itself.current
- The current (new) struct itself.
Link to this section Functions
diff(previous, current)
View Source
diff(Ecto.Schema.t() | nil, Ecto.Schema.t()) ::
{:ok, t()} | {:ok, :unchanged}
diff(Ecto.Schema.t() | nil, Ecto.Schema.t()) :: {:ok, t()} | {:ok, :unchanged}
Returns an EctoDiff.t/0
describing the difference between two given ecto structs.
The "previous" struct can be nil
, to represent an insert operation.
Examples
A new struct being inserted:
iex> {:ok, pet} = %{name: "Spot"} |> Pet.new() |> Repo.insert()
iex> {:ok, diff} = EctoDiff.diff(nil, pet)
iex> diff
#EctoDiff<
struct: Pet,
primary_key: %{id: 1},
effect: :added,
previous: #Pet<>,
current: #Pet<>,
changes: %{
id: {nil, 1},
name: {nil, "Spot"}
}
>
A struct being updated:
iex> {:ok, pet} = %{name: "Spot"} |> Pet.new() |> Repo.insert()
iex> {:ok, updated_pet} = pet |> Pet.update(%{name: "McFluffFace"}) |> Repo.update()
iex> {:ok, diff} = EctoDiff.diff(pet, updated_pet)
iex> diff
#EctoDiff<
struct: Pet,
primary_key: %{id: 1},
effect: :changed,
previous: #Pet<>,
current: #Pet<>,
changes: %{
name: {"Spot", "McFluffFace"}
}
>
A nested has_many association being updated:
iex> {:ok, initial_pet} =
...> %{name: "Spot", skills: [%{name: "Eating"}, %{name: "Sleeping"}, %{name: "Scratching"}]}
...> |> Pet.new()
...> |> Repo.insert()
iex> [eating_id, sleeping_id, _scratching_id] = Enum.map(initial_pet.skills, & &1.id)
iex> {:ok, updated_pet} =
...> initial_pet
...> |> Pet.update(%{skills: [%{id: eating_id}, %{id: sleeping_id, level: 2}, %{name: "Meowing"}]})
...> |> Repo.update()
iex> {:ok, diff} = EctoDiff.diff(initial_pet, updated_pet)
iex> diff
#EctoDiff<
struct: Pet,
primary_key: %{id: 1},
effect: :changed,
previous: #Pet<>,
current: #Pet<>,
changes: %{
skills: [
#EctoDiff<
struct: Skill,
primary_key: %{id: 2},
effect: :changed,
previous: #Skill<>,
current: #Skill<>,
changes: %{
level: {1, 2}
}
>,
#EctoDiff<
struct: Skill,
primary_key: %{id: 3},
effect: :deleted,
previous: #Skill<>,
current: #Skill<>,
changes: %{}
>,
#EctoDiff<
struct: Skill,
primary_key: %{id: 4},
effect: :added,
previous: #Skill<>,
current: #Skill<>,
changes: %{
id: {nil, 4},
pet_id: {nil, 1},
name: {nil, "Meowing"}
}
>
]
}
>