Skip to content

Support schemas with primary keys not named id #110

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions example/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule ExAudit.Test.User do

@derive {ExAudit.Tracker, except: [:transient_field]}

@primary_key {:user_id, :id, autogenerate: true}
schema "users" do
field :email, :string
field :name, :string
Expand Down
39 changes: 26 additions & 13 deletions lib/repo/queryable.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,17 @@ defmodule ExAudit.Queryable do
# from v in query,
# where: v.entity_id == subquery(from q in struct, select: q.id),
# where: v.entity_schema == ^struct
%{__struct__: struct, id: id} when nil not in [struct, id] ->
from(
v in query,
where: v.entity_id == ^id,
where: v.entity_schema == ^struct
)
%{__struct__: schema} when not is_nil(schema) ->
[primary_key] = schema.__schema__(:primary_key)
id = Map.get(struct, primary_key)

if not is_nil(id) do
from(
v in query,
where: v.entity_id == ^id,
where: v.entity_schema == ^schema
)
end
end

versions = Ecto.Repo.Queryable.all(module, query, Ecto.Repo.Supervisor.tuplet(module, opts))
Expand Down Expand Up @@ -74,13 +79,16 @@ defmodule ExAudit.Queryable do
end
end

def history_query(%{id: id, __struct__: struct}) do
def history_query(%{__struct__: schema} = struct) do
[primary_key] = schema.__schema__(:primary_key)
id = Map.get(struct, primary_key)

from(
v in version_schema(),
where: v.entity_id == ^id,
where: v.entity_schema == ^struct,
order_by: [desc: :recorded_at]
)
v in version_schema(),
where: v.entity_id == ^id,
where: v.entity_schema == ^schema,
order_by: [desc: :recorded_at]
)
end

@drop_fields [:__meta__, :__struct__]
Expand All @@ -103,7 +111,12 @@ defmodule ExAudit.Queryable do

# get the referenced struct as it exists now

struct = module.one(from(s in version.entity_schema, where: s.id == ^version.entity_id))
[primary_key] = version.entity_schema.__schema__(:primary_key)

struct =
module.one(
from(s in version.entity_schema, where: field(s, ^primary_key) == ^version.entity_id)
)

result = Enum.reduce(versions, struct, &_revert/2)

Expand Down
4 changes: 3 additions & 1 deletion lib/tracking/tracking.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ defmodule ExAudit.Tracking do
[]

patch ->
[primary_key] = schema.__schema__(:primary_key)

params = %{
entity_id: Map.get(old, :id) || Map.get(new, :id),
entity_id: Map.get(old, primary_key) || Map.get(new, primary_key),
entity_schema: schema,
patch: patch,
action: action
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule ExAudit.Test.Repo.Migrations.ChangeUserPrimaryKeyName do
use Ecto.Migration

def change do
rename table(:users), :id, to: :user_id
end
end
22 changes: 11 additions & 11 deletions test/assoc_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ defmodule AssocTest do
test "comment lifecycle tracked" do
user = Util.create_user()

ExAudit.track(actor_id: user.id)
ExAudit.track(actor_id: user.user_id)

params = %{
title: "Controversial post",
author_id: user.id,
author_id: user.user_id,
comments: [
%{
body: "lorem impusdrfnia",
author_id: user.id
author_id: user.user_id
}
]
}
Expand All @@ -26,7 +26,7 @@ defmodule AssocTest do

[%{actor_id: actor_id}] = comment_history = Repo.history(comment)
assert length(comment_history) == 1
assert actor_id == user.id
assert actor_id == user.user_id
end

test "structs configured as primitives are treated as primitives" do
Expand All @@ -52,23 +52,23 @@ defmodule AssocTest do
test "should track cascading deletions (before they happen)" do
user = Util.create_user()

ExAudit.track(actor_id: user.id)
ExAudit.track(actor_id: user.user_id)

params = %{
title: "Controversial post",
author_id: user.id,
author_id: user.user_id,
comments: [
%{
body: "lorem impusdrfnia",
author_id: user.id
author_id: user.user_id
},
%{
body: "That's a nice article",
author_id: user.id
author_id: user.user_id
},
%{
body: "We want more of this CONTENT",
author_id: user.id
author_id: user.user_id
}
]
}
Expand All @@ -95,15 +95,15 @@ defmodule AssocTest do
test "should return changesets from constraint errors" do
user = Util.create_user()

ch = UserGroup.changeset(%UserGroup{}, %{name: "a group", user_id: user.id})
ch = UserGroup.changeset(%UserGroup{}, %{name: "a group", user_id: user.user_id})
{:ok, _group} = Repo.insert(ch)

import Ecto.Changeset

deletion =
user
|> change
|> no_assoc_constraint(:groups)
|> no_assoc_constraint(:groups, name: :user_groups_user_id_fkey)

assert {:error, %Ecto.Changeset{}} = Repo.delete(deletion)
end
Expand Down
34 changes: 17 additions & 17 deletions test/ex_audit_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule ExAuditTest do
version =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:created
)
Expand All @@ -43,7 +43,7 @@ defmodule ExAuditTest do
version =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated
)
Expand All @@ -57,7 +57,7 @@ defmodule ExAuditTest do
version =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:deleted
)
Expand All @@ -75,11 +75,11 @@ defmodule ExAuditTest do

changeset =
BlogPost.changeset(%BlogPost{}, %{
author_id: user.id,
author_id: user.user_id,
title: "My First Post"
})

{:ok, blog_post} = Repo.insert(changeset, ex_audit_custom: [actor_id: user.id])
{:ok, blog_post} = Repo.insert(changeset, ex_audit_custom: [actor_id: user.user_id])

version =
Repo.one(
Expand All @@ -90,7 +90,7 @@ defmodule ExAuditTest do
)
)

assert version.actor_id == user.id
assert version.actor_id == user.user_id
end

test "should track insert_or_update!" do
Expand All @@ -110,7 +110,7 @@ defmodule ExAuditTest do
created =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:created
)
Expand All @@ -119,7 +119,7 @@ defmodule ExAuditTest do
updated =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated
)
Expand All @@ -128,7 +128,7 @@ defmodule ExAuditTest do
assert 2 =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
select: count(v.id)
)
Expand Down Expand Up @@ -163,7 +163,7 @@ defmodule ExAuditTest do
created =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:created
)
Expand All @@ -172,7 +172,7 @@ defmodule ExAuditTest do
updated =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated
)
Expand All @@ -181,7 +181,7 @@ defmodule ExAuditTest do
assert 2 =
Repo.one(
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User,
select: count(v.id)
)
Expand All @@ -206,11 +206,11 @@ defmodule ExAuditTest do

changeset =
BlogPost.changeset(%BlogPost{}, %{
author_id: user.id,
author_id: user.user_id,
title: "My Second Post"
})

ExAudit.track(actor_id: user.id)
ExAudit.track(actor_id: user.user_id)

{:ok, blog_post} = Repo.insert(changeset)

Expand All @@ -223,7 +223,7 @@ defmodule ExAuditTest do
)
)

assert version.actor_id == user.id
assert version.actor_id == user.user_id
end

test "does not track changes to ignored fields" do
Expand All @@ -239,7 +239,7 @@ defmodule ExAuditTest do

query =
from(v in Version,
where: v.entity_id == ^user.id,
where: v.entity_id == ^user.user_id,
where: v.entity_schema == ^User
)

Expand All @@ -261,7 +261,7 @@ defmodule ExAuditTest do
end

test "returns a queryable", %{user: user} do
assert user |> Repo.history_query() |> Repo.all() |> Enum.count() == 1
assert user |> Repo.history_query() |> Repo.all() |> Enum.count() == 1
end
end
end
10 changes: 5 additions & 5 deletions test/revert_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defmodule RevertTest do
test "should revert changes" do
user = Util.create_user()

ExAudit.track(actor_id: user.id)
ExAudit.track(actor_id: user.user_id)

user2 = Util.create_user("Horst Dieter Schaf", "[email protected]")

Expand All @@ -21,7 +21,7 @@ defmodule RevertTest do
version =
Repo.one(
from(v in Version,
where: v.entity_id == ^user2.id,
where: v.entity_id == ^user2.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated
)
Expand All @@ -36,7 +36,7 @@ defmodule RevertTest do
version_rollback =
Repo.one(
from(v in Version,
where: v.entity_id == ^user2.id,
where: v.entity_id == ^user2.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated,
where: v.rollback == true
Expand All @@ -56,7 +56,7 @@ defmodule RevertTest do
version_rollback =
Repo.one(
from(v in Version,
where: v.entity_id == ^user2.id,
where: v.entity_id == ^user2.user_id,
where: v.entity_schema == ^User,
where: v.action == ^:updated,
where: v.rollback == true,
Expand All @@ -74,6 +74,6 @@ defmodule RevertTest do
assert [version] = Repo.history(user)
assert {:ok, nil} = Repo.revert(version)

assert nil == Repo.get(User, user.id)
assert nil == Repo.get(User, user.user_id)
end
end