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

Add custom types for item_id and originator_id #20

Merged
merged 3 commits into from
May 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ The library source code is minimal and well tested. It is suggested to read the

```mix papertrail.install```

You might want to edit the types for `:event_id` and `:originator_id` if you're
using UUID or other types for your primary keys before you execute
`mix ecto.migrate`.

5. run the migration:

```mix ecto.migrate```
Expand All @@ -139,13 +143,25 @@ YES! Make sure you do the steps above.
| ------------- | ------- | -------------------------- | ------------------------ |
| event | String | either insert, update or delete | Library generates |
| item_type | String | model name of the reference record | Library generates |
| item_id | Integer | model id of the reference record | Library generates |
| item_id | configurable (Integer by default) | model id of the reference record | Library generates |
| item_changes | Map | all the changes in this version as a map | Library generates |
| originator_id | Integer | foreign key reference to the creator/owner of this change | Optionally set |
| originator_id | configurable (Integer by default) | foreign key reference to the creator/owner of this change | Optionally set |
| origin | String | short reference to origin(eg. worker:activity-checker, migration, admin:33) | Optionally set |
| meta | Map | any extra optional meta information about the version(eg. %{slug: "ausername", important: true}) | Optionally set |
| inserted_at | Date | inserted_at timestamp | Ecto generates |

#### Configuring the types

If you are using UUID or another type for your primary keys, you can configure
the PaperTrail.Version schema to use it.

```elixir
config :paper_trail, item_type: Ecto.UUID,
originator_type: Ecto.UUID
```

Remember to edit the types accordingly in the generated migration.

### Version origin references:
PaperTrail records have a string field called ```origin```. ```PaperTrail.insert/2```, ```PaperTrail.update/2```, ```PaperTrail.delete/2``` functions accept a second argument to describe the origin of this version:
```elixir
Expand Down
10 changes: 9 additions & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use Mix.Config

config :paper_trail, ecto_repos: [PaperTrail.Repo]
config :paper_trail, ecto_repos: [PaperTrail.Repo, PaperTrail.UUIDRepo]

config :paper_trail, repo: PaperTrail.Repo, originator: [name: :user, model: User]

Expand All @@ -11,3 +11,11 @@ config :paper_trail, PaperTrail.Repo,
database: "paper_trail_test",
hostname: "localhost",
poolsize: 10

config :paper_trail, PaperTrail.UUIDRepo,
adapter: Ecto.Adapters.Postgres,
username: "postgres",
password: "postgres",
database: "paper_trail_uuid_test",
hostname: "localhost",
poolsize: 10
9 changes: 6 additions & 3 deletions lib/version.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ defmodule PaperTrail.Version do

@setter PaperTrail.RepoClient.originator || nil

@item_type Application.get_env(:paper_trail, :item_type, :integer)
@originator_type Application.get_env(:paper_trail, :originator_type, :integer)

schema "versions" do
field :event, :string
field :item_type, :string
field :item_id, :integer
field :item_id, @item_type
field :item_changes, :map
field :originator_id, :integer
field :originator_id, @originator_type
field :origin, :string, read_after_writes: true
field :meta, :map

if @setter do
belongs_to @setter[:name], @setter[:model], define_field: false, foreign_key: :originator_id
belongs_to @setter[:name], @setter[:model], define_field: false, foreign_key: :originator_id, type: @originator_type
end

timestamps(updated_at: false)
Expand Down
18 changes: 9 additions & 9 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], []},
"db_connection": {:hex, :db_connection, "1.1.0", "b2b88db6d7d12f99997b584d09fad98e560b817a20dab6a526830e339f54cdb3", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]},
"decimal": {:hex, :decimal, "1.3.1", "157b3cedb2bfcb5359372a7766dd7a41091ad34578296e951f58a946fcab49c6", [:mix], []},
"earmark": {:hex, :earmark, "1.1.0", "8c2bf85d725050a92042bc1edf362621004d43ca6241c756f39612084e95487f", [:mix], []},
"ecto": {:hex, :ecto, "2.1.3", "ffb24e150b519a4c0e4c84f9eabc8587199389bc499195d5d1a93cd3b2d9a045", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, optional: true]}]},
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], []},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], []},
"postgrex": {:hex, :postgrex, "0.13.0", "e101ab47d0725955c5c8830ae8812412992e02e4bd9db09e17abb0a5d82d09c7", [:mix], [{:connection, "~> 1.0", [hex: :connection, optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, optional: false]}]}}
%{"connection": {:hex, :connection, "1.0.4", "a1cae72211f0eef17705aaededacac3eb30e6625b04a6117c1b2db6ace7d5976", [:mix], [], "hexpm"},
"db_connection": {:hex, :db_connection, "1.1.0", "b2b88db6d7d12f99997b584d09fad98e560b817a20dab6a526830e339f54cdb3", [:mix], [{:connection, "~> 1.0.2", [hex: :connection, repo: "hexpm", optional: false]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"decimal": {:hex, :decimal, "1.3.1", "157b3cedb2bfcb5359372a7766dd7a41091ad34578296e951f58a946fcab49c6", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.1.0", "8c2bf85d725050a92042bc1edf362621004d43ca6241c756f39612084e95487f", [:mix], [], "hexpm"},
"ecto": {:hex, :ecto, "2.1.3", "ffb24e150b519a4c0e4c84f9eabc8587199389bc499195d5d1a93cd3b2d9a045", [:mix], [{:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: true]}, {:decimal, "~> 1.2", [hex: :decimal, repo: "hexpm", optional: false]}, {:mariaex, "~> 0.8.0", [hex: :mariaex, repo: "hexpm", optional: true]}, {:poison, "~> 2.2 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:poolboy, "~> 1.5", [hex: :poolboy, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.13.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:sbroker, "~> 1.0", [hex: :sbroker, repo: "hexpm", optional: true]}], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.14.5", "c0433c8117e948404d93ca69411dd575ec6be39b47802e81ca8d91017a0cf83c", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, repo: "hexpm", optional: false]}], "hexpm"},
"poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"},
"poolboy": {:hex, :poolboy, "1.5.1", "6b46163901cfd0a1b43d692657ed9d7e599853b3b21b95ae5ae0a777cf9b6ca8", [:rebar], [], "hexpm"},
"postgrex": {:hex, :postgrex, "0.13.0", "e101ab47d0725955c5c8830ae8812412992e02e4bd9db09e17abb0a5d82d09c7", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 1.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm"}}
12 changes: 12 additions & 0 deletions priv/uuid_repo/migrations/20170525133833_create_uuid_products.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule PaperTrail.UUIDRepo.Migrations.CreateUuidProducts do
use Ecto.Migration

def change do
create table(:products, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false

timestamps()
end
end
end
12 changes: 12 additions & 0 deletions priv/uuid_repo/migrations/20170525142546_create_admins.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule PaperTrail.UUIDRepo.Migrations.CreateAdmins do
use Ecto.Migration

def change do
create table(:admins, primary_key: false) do
add :id, :binary_id, primary_key: true
add :email, :string, null: false

timestamps()
end
end
end
22 changes: 22 additions & 0 deletions priv/uuid_repo/migrations/20170525142612_create_versions.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
defmodule PaperTrail.UUIDRepo.Migrations.CreateVersions do
use Ecto.Migration

def change do
create table(:versions) do
add :event, :string, null: false, size: 10
add :item_type, :string, null: false
add :item_id, :binary_id
add :item_changes, :map, null: false
add :originator_id, references(:admins, type: :binary_id)
add :origin, :string, size: 50
add :meta, :map

add :inserted_at, :utc_datetime, null: false
end

create index(:versions, [:originator_id])
create index(:versions, [:item_id, :item_type])
create index(:versions, [:event, :item_type])
create index(:versions, [:item_type, :inserted_at])
end
end
52 changes: 52 additions & 0 deletions test/paper_trail/uuid_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule PaperTrailTest.UUIDTest do
use ExUnit.Case
import PaperTrail.RepoClient, only: [repo: 0]
alias PaperTrail.Version
import Ecto.Query


setup do
Application.put_env(:paper_trail, :repo, PaperTrail.UUIDRepo)
Application.put_env(:paper_trail, :originator, [name: :admin, model: Admin])
Application.put_env(:paper_trail, :originator_type, Ecto.UUID)
Application.put_env(:paper_trail, :item_type, Ecto.UUID)
Code.eval_file("lib/paper_trail.ex")
Code.eval_file("lib/version.ex")
repo().delete_all(Version)
repo().delete_all(Admin)
repo().delete_all(Product)
:ok
end

test "creates versions with models that have a UUID primary key" do
product =
%Product{}
|> Product.changeset(%{name: "Hair Cream"})
|> PaperTrail.insert!

version = Version |> last |> repo.one

assert version.item_id == product.id
assert version.item_type == "Product"
end

test "handles originators with a UUID primary key" do
admin =
%Admin{}
|> Admin.changeset(%{email: "admin@example.com"})
|> repo.insert!

product =
%Product{}
|> Product.changeset(%{name: "Hair Cream"})
|> PaperTrail.insert!(originator: admin)

version =
Version
|> last
|> repo.one
|> repo.preload(:admin)

assert version.admin == admin
end
end
4 changes: 4 additions & 0 deletions test/support/repo.ex → test/support/repos.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ defmodule PaperTrail.Repo do
use Ecto.Repo, otp_app: :paper_trail
end

defmodule PaperTrail.UUIDRepo do
use Ecto.Repo, otp_app: :paper_trail
end

defmodule User do
use Ecto.Schema

Expand Down
36 changes: 36 additions & 0 deletions test/support/uuid_models.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
defmodule Product do
use Ecto.Schema

import Ecto.Changeset

@primary_key {:id, :binary_id, autogenerate: true}
schema "products" do
field :name, :string

timestamps()
end

def changeset(model, params \\ %{}) do
model
|> cast(params, [:name])
|> validate_required([:name])
end
end

defmodule Admin do
use Ecto.Schema
import Ecto.Changeset

@primary_key {:id, :binary_id, autogenerate: true}
schema "admins" do
field :email, :string

timestamps()
end

def changeset(model, params \\ %{}) do
model
|> cast(params, [:email])
|> validate_required([:email])
end
end
6 changes: 4 additions & 2 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
Mix.Task.run "ecto.create", ~w(-r PaperTrail.Repo)
Mix.Task.run "ecto.migrate", ~w(-r PaperTrail.Repo)
Mix.Task.run "ecto.create"
Mix.Task.run "ecto.migrate"

PaperTrail.Repo.start_link
PaperTrail.UUIDRepo.start_link

Code.require_file("test/support/simple_models.exs")
Code.require_file("test/support/strict_models.exs")
Code.require_file("test/support/uuid_models.exs")

ExUnit.configure seed: 0

Expand Down