Current section

Files

Jump to
paper_trail lib paper_trail.ex
Raw

lib/paper_trail.ex

defmodule PaperTrail do
import Ecto.Changeset
alias PaperTrail.Version
alias PaperTrail.RepoClient
alias PaperTrail.Serializer
defdelegate get_version(record), to: PaperTrail.VersionQueries
defdelegate get_version(model_or_record, id_or_options), to: PaperTrail.VersionQueries
defdelegate get_version(model, id, options), to: PaperTrail.VersionQueries
defdelegate get_versions(record), to: PaperTrail.VersionQueries
defdelegate get_versions(model_or_record, id_or_options), to: PaperTrail.VersionQueries
defdelegate get_versions(model, id, options), to: PaperTrail.VersionQueries
defdelegate get_current_model(version), to: PaperTrail.VersionQueries
defdelegate make_version_struct(version, model, options), to: Serializer
defdelegate serialize(data), to: Serializer
defdelegate get_sequence_id(table_name), to: Serializer
defdelegate add_prefix(schema, prefix), to: Serializer
defdelegate get_item_type(data), to: Serializer
defdelegate get_model_id(model), to: Serializer
@doc """
Inserts a record to the database with a related version insertion in one transaction
"""
def insert(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil, model_key: :model, version_key: :version, ecto_options: []]) do
PaperTrail.Multi.new()
|> PaperTrail.Multi.insert(changeset, options)
|> PaperTrail.Multi.commit()
end
@doc """
Same as insert/2 but returns only the model struct or raises if the changeset is invalid.
"""
def insert!(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil, model_key: :model, version_key: :version, ecto_options: []]) do
repo = RepoClient.repo()
ecto_options = options[:ecto_options] || []
repo.transaction(fn ->
case RepoClient.strict_mode() do
true ->
version_id = get_sequence_id("versions") + 1
changeset_data =
Map.get(changeset, :data, changeset)
|> Map.merge(%{
id: get_sequence_id(changeset) + 1,
first_version_id: version_id,
current_version_id: version_id
})
initial_version =
make_version_struct(%{event: "insert"}, changeset_data, options)
|> repo.insert!
updated_changeset =
changeset
|> change(%{
first_version_id: initial_version.id,
current_version_id: initial_version.id
})
model = repo.insert!(updated_changeset, ecto_options)
target_version = make_version_struct(%{event: "insert"}, model, options) |> serialize()
Version.changeset(initial_version, target_version) |> repo.update!
model
_ ->
model = repo.insert!(changeset, ecto_options)
make_version_struct(%{event: "insert"}, model, options) |> repo.insert!
model
end
end)
|> elem(1)
end
@doc """
Updates a record from the database with a related version insertion in one transaction
"""
def update(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do
PaperTrail.Multi.new()
|> PaperTrail.Multi.update(changeset, options)
|> PaperTrail.Multi.commit()
end
@doc """
Same as update/2 but returns only the model struct or raises if the changeset is invalid.
"""
def update!(changeset, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do
repo = PaperTrail.RepoClient.repo()
client = PaperTrail.RepoClient
repo.transaction(fn ->
case client.strict_mode() do
true ->
version_data =
changeset.data
|> Map.merge(%{
current_version_id: get_sequence_id("versions")
})
target_changeset = changeset |> Map.merge(%{data: version_data})
target_version = make_version_struct(%{event: "update"}, target_changeset, options)
initial_version = repo.insert!(target_version)
updated_changeset = changeset |> change(%{current_version_id: initial_version.id})
model = repo.update!(updated_changeset)
new_item_changes =
initial_version.item_changes
|> Map.merge(%{
current_version_id: initial_version.id
})
initial_version |> change(%{item_changes: new_item_changes}) |> repo.update!
model
_ ->
model = repo.update!(changeset)
version_struct = make_version_struct(%{event: "update"}, changeset, options)
repo.insert!(version_struct)
model
end
end)
|> elem(1)
end
@doc """
Deletes a record from the database with a related version insertion in one transaction
"""
def delete(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do
PaperTrail.Multi.new()
|> PaperTrail.Multi.delete(struct, options)
|> PaperTrail.Multi.commit()
end
@doc """
Same as delete/2 but returns only the model struct or raises if the changeset is invalid.
"""
def delete!(struct, options \\ [origin: nil, meta: nil, originator: nil, prefix: nil]) do
repo = PaperTrail.RepoClient.repo()
repo.transaction(fn ->
model = repo.delete!(struct, options)
version_struct = make_version_struct(%{event: "delete"}, struct, options)
repo.insert!(version_struct, options)
model
end)
|> elem(1)
end
end