Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dump fields using Ecto when serializing changes #83

Merged
merged 9 commits into from
Nov 28, 2020
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
erl_crash.dump
*.ez
.elixir_ls
.tool-versions
2 changes: 2 additions & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,5 @@ config :paper_trail, PaperTrail.UUIDRepo,
database: "paper_trail_uuid_test",
hostname: System.get_env("PG_HOST"),
poolsize: 10

config :logger, level: :warn
112 changes: 8 additions & 104 deletions lib/paper_trail.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule PaperTrail do

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
Expand All @@ -11,6 +12,12 @@ defmodule PaperTrail do
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
Expand All @@ -36,7 +43,7 @@ defmodule PaperTrail do
changeset_data =
Map.get(changeset, :data, changeset)
|> Map.merge(%{
id: get_sequence_from_model(changeset) + 1,
id: get_sequence_id(changeset) + 1,
first_version_id: version_id,
current_version_id: version_id
})
Expand Down Expand Up @@ -139,107 +146,4 @@ defmodule PaperTrail do
end)
|> elem(1)
end

defp make_version_struct(%{event: "insert"}, model, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "insert",
item_type: get_item_type(model),
item_id: get_model_id(model),
item_changes: serialize(model),
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp make_version_struct(%{event: "update"}, changeset, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "update",
item_type: get_item_type(changeset),
item_id: get_model_id(changeset),
item_changes: changeset.changes,
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp make_version_struct(%{event: "delete"}, model_or_changeset, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "delete",
item_type: get_item_type(model_or_changeset),
item_id: get_model_id(model_or_changeset),
item_changes: serialize(model_or_changeset),
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp get_sequence_from_model(changeset) do
table_name =
case Map.get(changeset, :data) do
nil -> changeset.__struct__.__schema__(:source)
_ -> changeset.data.__struct__.__schema__(:source)
end

get_sequence_id(table_name)
end

defp get_sequence_id(table_name) do
Ecto.Adapters.SQL.query!(RepoClient.repo(), "select last_value FROM #{table_name}_id_seq").rows
|> List.first()
|> List.first()
end

defp serialize(%Ecto.Changeset{data: data}), do: serialize(data)

defp serialize(model) do
relationships = model.__struct__.__schema__(:associations)
Map.drop(model, [:__struct__, :__meta__] ++ relationships)
end

defp add_prefix(changeset, nil), do: changeset
defp add_prefix(changeset, prefix), do: Ecto.put_meta(changeset, prefix: prefix)

defp get_item_type(%Ecto.Changeset{data: data}), do: get_item_type(data)
defp get_item_type(model), do: model.__struct__ |> Module.split() |> List.last()

def get_model_id(%Ecto.Changeset{data: data}), do: get_model_id(data)

def get_model_id(model) do
{_, model_id} = List.first(Ecto.primary_key(model))

case PaperTrail.Version.__schema__(:type, :item_id) do
:integer ->
model_id

_ ->
"#{model_id}"
end
end
end
112 changes: 8 additions & 104 deletions lib/paper_trail/multi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule PaperTrail.Multi do
alias PaperTrail
alias PaperTrail.Version
alias PaperTrail.RepoClient
alias PaperTrail.Serializer

defdelegate new(), to: Ecto.Multi
defdelegate append(lhs, rhs), to: Ecto.Multi
Expand All @@ -14,6 +15,12 @@ defmodule PaperTrail.Multi do
defdelegate run(multi, name, run), to: Ecto.Multi
defdelegate run(multi, name, mod, fun, args), to: Ecto.Multi
defdelegate to_list(multi), to: Ecto.Multi
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

def insert(%Ecto.Multi{} = multi, changeset, options \\ [
origin: nil, meta: nil, originator: nil, prefix: nil, model_key: :model, version_key: :version, ecto_options: []
Expand All @@ -31,7 +38,7 @@ defmodule PaperTrail.Multi do
changeset_data =
Map.get(changeset, :data, changeset)
|> Map.merge(%{
id: get_sequence_from_model(changeset) + 1,
id: get_sequence_id(changeset) + 1,
first_version_id: version_id,
current_version_id: version_id
})
Expand Down Expand Up @@ -146,107 +153,4 @@ defmodule PaperTrail.Multi do
end
end
end

defp make_version_struct(%{event: "insert"}, model, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "insert",
item_type: get_item_type(model),
item_id: get_model_id(model),
item_changes: serialize(model),
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp make_version_struct(%{event: "update"}, changeset, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "update",
item_type: get_item_type(changeset),
item_id: get_model_id(changeset),
item_changes: changeset.changes,
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp make_version_struct(%{event: "delete"}, model_or_changeset, options) do
originator = PaperTrail.RepoClient.originator()
originator_ref = options[originator[:name]] || options[:originator]

%Version{
event: "delete",
item_type: get_item_type(model_or_changeset),
item_id: get_model_id(model_or_changeset),
item_changes: serialize(model_or_changeset),
originator_id:
case originator_ref do
nil -> nil
_ -> originator_ref |> Map.get(:id)
end,
origin: options[:origin],
meta: options[:meta]
}
|> add_prefix(options[:prefix])
end

defp get_sequence_from_model(changeset) do
table_name =
case Map.get(changeset, :data) do
nil -> changeset.__struct__.__schema__(:source)
_ -> changeset.data.__struct__.__schema__(:source)
end

get_sequence_id(table_name)
end

defp get_sequence_id(table_name) do
Ecto.Adapters.SQL.query!(RepoClient.repo(), "select last_value FROM #{table_name}_id_seq").rows
|> List.first()
|> List.first()
end

defp serialize(%Ecto.Changeset{data: data}), do: serialize(data)

defp serialize(model) do
relationships = model.__struct__.__schema__(:associations)
Map.drop(model, [:__struct__, :__meta__] ++ relationships)
end

defp add_prefix(changeset, nil), do: changeset
defp add_prefix(changeset, prefix), do: Ecto.put_meta(changeset, prefix: prefix)

defp get_item_type(%Ecto.Changeset{data: data}), do: get_item_type(data)
defp get_item_type(model), do: model.__struct__ |> Module.split() |> List.last()

defp get_model_id(%Ecto.Changeset{data: data}), do: get_model_id(data)

defp get_model_id(model) do
{_, model_id} = List.first(Ecto.primary_key(model))

case PaperTrail.Version.__schema__(:type, :item_id) do
:integer ->
model_id

_ ->
"#{model_id}"
end
end
end
Loading