From f725ba6fc4b3453105f5353b9a85bfb76efa9fe9 Mon Sep 17 00:00:00 2001 From: Izel Nakri Date: Fri, 15 Jul 2016 00:03:09 +0200 Subject: [PATCH] some logic added --- README.md | 9 +- lib/paper_trail.ex | 90 +++++++++++++++++++ lib/version.ex | 33 +++++++ .../20160619190936_add_versions.exs | 16 ++++ 4 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 lib/version.ex create mode 100644 priv/repo/migrations/20160619190936_add_versions.exs diff --git a/README.md b/README.md index b9571266..7746a352 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ # PaperTrail +```mix papertrail.install``` + +PaperTrail.create/1, PaperTrail.update/1, PaperTrail.destroy/1 + +PaperTrail.get_version\2, PaperTrail.get_version\1 PaperTrail.get_versions\2, PaperTrail.get_versions\1 + +I will write some tests for this library. + **TODO: Add description** ## Installation @@ -17,4 +25,3 @@ If [available in Hex](https://hex.pm/docs/publish), the package can be installed def application do [applications: [:paper_trail]] end - diff --git a/lib/paper_trail.ex b/lib/paper_trail.ex index f098b73b..7fcd101c 100644 --- a/lib/paper_trail.ex +++ b/lib/paper_trail.ex @@ -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 diff --git a/lib/version.ex b/lib/version.ex new file mode 100644 index 00000000..5dff4fed --- /dev/null +++ b/lib/version.ex @@ -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 diff --git a/priv/repo/migrations/20160619190936_add_versions.exs b/priv/repo/migrations/20160619190936_add_versions.exs new file mode 100644 index 00000000..425473bc --- /dev/null +++ b/priv/repo/migrations/20160619190936_add_versions.exs @@ -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