-
Notifications
You must be signed in to change notification settings - Fork 92
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
147 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,92 @@ | ||
defmodule PaperTrail do | ||
alias Ecto.Multi | ||
import Ecto.Query | ||
alias Model.Version | ||
|
||
def get_versions(model, id) do | ||
item_type = model |> Module.split |> List.last | ||
version_query(item_type, id) |> Application.Repo.all | ||
end | ||
|
||
def get_versions(changeset) do | ||
item_type = changeset.__struct__ |> Module.split |> List.last | ||
version_query(item_type, changeset.id) |> Application.Repo.all # where id, item_type last inserted_at | ||
end | ||
|
||
def get_version(model, id) do | ||
item_type = Module.split(model) |> List.last | ||
version_query(item_type, id) |> Application.Repo.one | ||
end | ||
|
||
def get_version(changeset) do | ||
item_type = changeset.__struct__ |> Module.split |> List.last | ||
last(version_query(item_type, changeset.id)) |> Application.Repo.one # where id, item_type last inserted_at | ||
end | ||
|
||
defp version_query(item_type, id) do | ||
from v in Version, | ||
where: v.item_type == ^item_type and v.item_id == ^id | ||
end | ||
|
||
# changeset = Model.changeset(Ecto.Repo.get(Model, id), params) | ||
|
||
def insert(struct, meta \\ nil) do | ||
Multi.new | ||
|> Multi.insert(:model, struct) | ||
|> Multi.run(:version, fn %{model: model} -> | ||
version = make_version_struct(%{event: "create"}, model, meta) | ||
Application.Repo.insert(version) | ||
end) | ||
|> Application.Repo.transaction | ||
end | ||
|
||
def update(changeset, meta \\ nil) do | ||
Multi.new | ||
|> Multi.update(:model, changeset) | ||
|> Multi.run(:version, fn %{model: model} -> | ||
version = make_version_struct(%{event: "update"}, changeset, meta) | ||
Application.Repo.insert(version) | ||
end) | ||
|> Application.Repo.transaction | ||
end | ||
|
||
def delete(struct, meta \\ nil) do | ||
Multi.new | ||
|> Multi.delete(:model, struct) | ||
|> Multi.run(:version, fn %{model: model} -> | ||
version = make_version_struct(%{event: "destroy"}, model, meta) | ||
Application.Repo.insert(version) | ||
end) | ||
|> Application.Repo.transaction | ||
end | ||
|
||
def make_version_struct(%{event: "create"}, model, meta) do | ||
%Version{ | ||
event: "create", | ||
item_type: model.__struct__ |> Module.split |> List.last, | ||
item_id: model.id, | ||
item_changes: Map.drop(model, [:__struct__, :__meta__]), | ||
meta: meta | ||
} | ||
end | ||
|
||
def make_version_struct(%{event: "update"}, changeset, meta) do | ||
%Version{ | ||
event: "create", | ||
item_type: changeset.data.__struct__ |> Module.split |> List.last, | ||
item_id: changeset.data.id, | ||
item_changes: changeset.changes, | ||
meta: meta | ||
} | ||
end | ||
|
||
def make_version_struct(%{event: "destroy"}, model, meta) do | ||
%Version{ | ||
event: "destroy", | ||
item_type: model.__struct__ |> Module.split |> List.last, | ||
item_id: model.id, | ||
item_changes: Map.drop(model, [:__struct__, :__meta__]), | ||
meta: meta | ||
} | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
defmodule Model.Version do | ||
use Ecto.Schema | ||
|
||
import Ecto | ||
import Ecto.Changeset | ||
import Ecto.Query | ||
# how to record column changes in migration | ||
|
||
schema "versions" do | ||
field :event, :string | ||
field :item_type, :string | ||
field :item_id, :integer | ||
field :item_changes, :map | ||
field :meta, :map | ||
field :originator, :string | ||
|
||
timestamps(updated_at: false) | ||
end | ||
|
||
@required_fields ~w(item_type item_id event created_at) | ||
@optional_fields ~w(meta originator) | ||
|
||
@doc """ | ||
Creates a changeset based on the `model` and `params`. | ||
If no params are provided, an invalid changeset is returned | ||
with no validation performed. | ||
""" | ||
def changeset(model, params \\ :empty) do | ||
model | ||
|> cast(params, @required_fields, @optional_fields) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
defmodule Repo.Migrations.AddVersions do | ||
use Ecto.Migration | ||
|
||
def change do | ||
create table(:versions) do | ||
add :event, :string | ||
add :item_type, :string | ||
add :item_id, :integer | ||
add :item_changes, :map | ||
add :meta, :map | ||
add :originator, :string | ||
|
||
add :inserted_at, :datetime, null: false | ||
end | ||
end | ||
end |