Skip to content

Commit

Permalink
strict_mode tests added
Browse files Browse the repository at this point in the history
  • Loading branch information
izelnakri committed Mar 12, 2017
1 parent b821fd8 commit 750a305
Show file tree
Hide file tree
Showing 10 changed files with 532 additions and 153 deletions.
130 changes: 68 additions & 62 deletions lib/paper_trail.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ defmodule PaperTrail do
alias PaperTrail.Version

@repo PaperTrail.RepoClient.repo
@strict_mode PaperTrail.RepoClient.strict_mode
@client PaperTrail.RepoClient

@doc """
Gets all the versions of a record given a module and its id
Expand Down Expand Up @@ -47,69 +47,75 @@ defmodule PaperTrail do
@doc """
Inserts a record to the database with a related version insertion in one transaction
"""
def insert(changeset, options \\ [produced_by: nil, meta: nil])
def insert(changeset, options) when @strict_mode do
Multi.new
|> Multi.run(:version, fn %{} ->
version_id = get_sequence_id("versions")
version_data = changeset.data |> Map.merge(%{
id: get_sequence_from_model(changeset),
first_version_id: version_id,
current_version_id: version_id
})
initial_version = make_version_struct(%{event: "insert"}, version_data, options)
@repo.insert(initial_version)
end)
|> Multi.run(:model, fn %{version: version} ->
updated_changeset = changeset |> change(%{
first_version_id: version.id, current_version_id: version.id
})
Repo.insert(updated_changeset)
end)
|> @repo.transaction
end
def insert(changeset, options) do
Multi.new
|> Multi.insert(:model, changeset)
|> Multi.run(:version, fn %{model: model} ->
version = make_version_struct(%{event: "insert"}, model, options)
@repo.insert(version)
end)
|> @repo.transaction
def insert(changeset, options \\ [sourced_by: nil, meta: nil]) do
case @client.strict_mode() do
true ->
Multi.new
|> Multi.run(:initial_version, fn %{} ->
version_id = get_sequence_id("versions") + 1
changeset_data = changeset.data |> Map.merge(%{
id: get_sequence_from_model(changeset) + 1,
first_version_id: version_id,
current_version_id: version_id
})
initial_version = make_version_struct(%{event: "insert"}, changeset_data, options)
@repo.insert(initial_version)
end)
|> Multi.run(:model, fn %{initial_version: initial_version} ->
updated_changeset = changeset |> change(%{
first_version_id: initial_version.id, current_version_id: initial_version.id
})
@repo.insert(updated_changeset)
end)
|> Multi.run(:version, fn %{initial_version: initial_version, model: model} ->
target_version = make_version_struct(%{event: "insert"}, model, options) |> serialize()
Version.changeset(initial_version, target_version) |> @repo.update
end)
|> @repo.transaction
_ ->
Multi.new
|> Multi.insert(:model, changeset)
|> Multi.run(:version, fn %{model: model} ->
version = make_version_struct(%{event: "insert"}, model, options)
@repo.insert(version)
end)
|> @repo.transaction
end
end

@doc """
Updates a record from the database with a related version insertion in one transaction
"""
def update(changeset, options \\ [produced_by: nil, meta: nil])
def update(changeset, options) when @strict_mode do
Multi.new
|> Multi.run(:version, fn %{} ->
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)
@repo.insert(target_version)
end)
|> Multi.run(:model, fn %{version: version} ->
updated_changeset = changeset |> change(%{current_version_id: version.id})
Repo.update(updated_changeset)
end)
|> @repo.transaction
end
def update(changeset, options) do
Multi.new
|> Multi.update(:model, changeset)
|> Multi.run(:version, fn %{model: _model} ->
version = make_version_struct(%{event: "update"}, changeset, options)
@repo.insert(version)
end)
|> @repo.transaction
def update(changeset, options \\ [sourced_by: nil, meta: nil]) do
case @client.strict_mode() do
true ->
Multi.new
|> Multi.run(:version, fn %{} ->
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)
@repo.insert(target_version)
end)
|> Multi.run(:model, fn %{version: version} ->
updated_changeset = changeset |> change(%{current_version_id: version.id})
@repo.update(updated_changeset)
end)
|> @repo.transaction
_ ->
Multi.new
|> Multi.update(:model, changeset)
|> Multi.run(:version, fn %{model: _model} ->
version = make_version_struct(%{event: "update"}, changeset, options)
@repo.insert(version)
end)
|> @repo.transaction
end
end

@doc """
Deletes a record from the database with a related version insertion in one transaction
"""
def delete(struct, options \\ [produced_by: nil, meta: nil]) do
def delete(struct, options \\ [sourced_by: nil, meta: nil]) do
Multi.new
|> Multi.delete(:model, struct)
|> Multi.run(:version, fn %{} ->
Expand All @@ -119,14 +125,14 @@ defmodule PaperTrail do
|> @repo.transaction
end

defp make_version_struct(event_list, model, options \\ [produced_by: nil, meta: nil])
defp make_version_struct(event_list, model, options \\ [])
defp make_version_struct(%{event: "insert"}, model, options) do
%Version{
event: "insert",
item_type: model.__struct__ |> Module.split |> List.last,
item_id: model.id,
item_changes: filter_item_changes(model),
produced_by: options[:produced_by],
item_changes: serialize(model),
sourced_by: options[:sourced_by],
meta: options[:meta]
}
end
Expand All @@ -136,7 +142,7 @@ defmodule PaperTrail do
item_type: changeset.data.__struct__ |> Module.split |> List.last,
item_id: changeset.data.id,
item_changes: changeset.changes,
produced_by: options[:produced_by],
sourced_by: options[:sourced_by],
meta: options[:meta]
}
end
Expand All @@ -145,8 +151,8 @@ defmodule PaperTrail do
event: "delete",
item_type: model.__struct__ |> Module.split |> List.last,
item_id: model.id,
item_changes: filter_item_changes(model),
produced_by: options[:produced_by],
item_changes: serialize(model),
sourced_by: options[:sourced_by],
meta: options[:meta]
}
end
Expand All @@ -157,12 +163,12 @@ defmodule PaperTrail do
end

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

defp filter_item_changes(model) do
defp serialize(model) do
relationships = model.__struct__.__schema__(:associations)
Map.drop(model, [:__struct__, :__meta__] ++ relationships)
end
Expand Down
7 changes: 4 additions & 3 deletions lib/version.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,17 @@ defmodule PaperTrail.Version do
field :item_type, :string
field :item_id, :integer
field :item_changes, :map
# add :producer_id # in future
field :produced_by, :string
field :sourced_by, :string
field :meta, :map

# belongs_to :owner

timestamps(updated_at: false)
end

def changeset(model, params \\ :empty) do
model
|> cast(params, [:item_changes, :meta])
|> cast(params, [:item_type, :item_id, :item_changes, :sourced_by, :meta])
|> validate_required([:event, :item_type, :item_id, :item_changes])
end

Expand Down
4 changes: 2 additions & 2 deletions priv/repo/migrations/20160619190936_add_versions.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ defmodule Repo.Migrations.AddVersions do
add :item_type, :string
add :item_id, :integer
add :item_changes, :map
# add :producer_id # in future
add :produced_by, :string, size: 50
# add :owner_id # in future
add :sourced_by, :string, size: 50
add :meta, :map

add :inserted_at, :utc_datetime, null: false
Expand Down
4 changes: 2 additions & 2 deletions priv/repo/migrations/20170319190938_add_strict_companies.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ defmodule Repo.Migrations.CreateStrictCompanies do
add :twitter, :string
add :founded_in, :string

add :first_version_id, references(:versions)
add :current_version_id, references(:versions)
add :first_version_id, references(:versions), null: false
add :current_version_id, references(:versions), null: false

timestamps()
end
Expand Down
4 changes: 2 additions & 2 deletions priv/repo/migrations/20170319190940_add_strict_people.exs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ defmodule Repo.Migrations.CreateStrictPeople do
add :birthdate, :date

add :company_id, references(:strict_companies), null: false
add :first_version_id, references(:versions)
add :current_version_id, references(:versions)
add :first_version_id, references(:versions), null: false
add :current_version_id, references(:versions), null: false

timestamps()
end
Expand Down
8 changes: 4 additions & 4 deletions test/helpers/strict_model_definitions.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ defmodule StrictCompany do
field :founded_in, :string

belongs_to :first_version, PaperTrail.Version
belongs_to :current_version, PaperTrail.Version
belongs_to :current_version, PaperTrail.Version, on_replace: :update

has_many :people, SimplePerson, foreign_key: :company_id
has_many :people, StrictPerson, foreign_key: :company_id

timestamps()
end
Expand Down Expand Up @@ -49,8 +49,8 @@ defmodule StrictPerson do
field :birthdate, Ecto.Date

belongs_to :first_version, PaperTrail.Version
belongs_to :current_version, PaperTrail.Version
belongs_to :company, SimpleCompany, foreign_key: :company_id
belongs_to :current_version, PaperTrail.Version, on_replace: :update
belongs_to :company, StrictCompany, foreign_key: :company_id

timestamps()
end
Expand Down
3 changes: 2 additions & 1 deletion test/paper_trail/version_queries_test.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule PaperTrailTest.VersionQueries do
use ExUnit.Case

alias PaperTrail.Version
alias SimpleCompany, as: Company
alias SimplePerson, as: Person
Expand All @@ -11,7 +12,7 @@ defmodule PaperTrailTest.VersionQueries do
setup_all do
@repo.delete_all(Person)
@repo.delete_all(Company)
@repo.delete_all(PaperTrail.Version)
@repo.delete_all(Version)

Company.changeset(%Company{}, %{
name: "Acme LLC", is_active: true, city: "Greenwich", people: []
Expand Down
Loading

0 comments on commit 750a305

Please sign in to comment.