Skip to content

Commit

Permalink
Merge pull request #103 from aifrak/add-id-type
Browse files Browse the repository at this point in the history
improvement: add :primary_key_type option
  • Loading branch information
rgraff authored Aug 19, 2024
2 parents 300174b + 5d6859e commit 6c6d772
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 2 deletions.
1 change: 1 addition & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ spark_locals_without_parens = [
include_versions?: 1,
mixin: 1,
on_actions: 1,
primary_key_type: 1,
public?: 1,
reference_source?: 1,
relationship_opts: 1,
Expand Down
1 change: 1 addition & 0 deletions documentation/dsls/DSL:-AshPaperTrail.Resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ A section for configuring how versioning is derived for the resource.

| Name | Type | Default | Docs |
|------|------|---------|------|
| [`primary_key_type`](#paper_trail-primary_key_type){: #paper_trail-primary_key_type } | `atom` | `:uuid` | Set the type of the column `:id`. |
| [`attributes_as_attributes`](#paper_trail-attributes_as_attributes){: #paper_trail-attributes_as_attributes } | `list(atom)` | `[]` | A set of attributes that should be set as attributes on the version resource, instead of stored in the freeform `changes` map attribute. |
| [`change_tracking_mode`](#paper_trail-change_tracking_mode){: #paper_trail-change_tracking_mode } | `:snapshot \| :changes_only \| :full_diff` | `:snapshot` | Changes are stored in a map attribute called `changes`. The `change_tracking_mode` determines what's stored. See the getting started guide for more. |
| [`ignore_attributes`](#paper_trail-ignore_attributes){: #paper_trail-ignore_attributes } | `list(atom)` | `[]` | A list of attributes that should be ignored. Typically you'll want to ignore your timestamps. The primary key is always ignored. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use Ash.Resource,
]

paper_trail do
primary_key_type :uuid_v7 # default is :uuid
change_tracking_mode :changes_only # default is :snapshot
store_action_name? true # default is false
ignore_attributes [:inserted_at, :updated_at] # the primary keys are always ignored
Expand Down
5 changes: 5 additions & 0 deletions lib/resource/info.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
defmodule AshPaperTrail.Resource.Info do
@moduledoc "Introspection helpers for `AshPaperTrail.Resource`"

@spec primary_key_type(Spark.Dsl.t() | Ash.Resource.t()) :: atom
def primary_key_type(resource) do
Spark.Dsl.Extension.get_opt(resource, [:paper_trail], :primary_key_type, :uuid)
end

@spec attributes_as_attributes(Spark.Dsl.t() | Ash.Resource.t()) :: [atom]
def attributes_as_attributes(resource) do
Spark.Dsl.Extension.get_opt(resource, [:paper_trail], :attributes_as_attributes, [])
Expand Down
5 changes: 5 additions & 0 deletions lib/resource/resource.ex
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ defmodule AshPaperTrail.Resource do
""",
entities: [@belongs_to_actor],
schema: [
primary_key_type: [
type: :atom,
default: :uuid,
doc: "Set the type of the column `:id`."
],
attributes_as_attributes: [
type: {:list, :atom},
default: [],
Expand Down
7 changes: 6 additions & 1 deletion lib/resource/transformers/create_version_resource.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ defmodule AshPaperTrail.Resource.Transformers.CreateVersionResource do
version_module = AshPaperTrail.Resource.Info.version_resource(dsl_state)
module = Transformer.get_persisted(dsl_state, :module)

primary_key_type = AshPaperTrail.Resource.Info.primary_key_type(dsl_state)
ignore_attributes = AshPaperTrail.Resource.Info.ignore_attributes(dsl_state)
attributes_as_attributes = AshPaperTrail.Resource.Info.attributes_as_attributes(dsl_state)
belongs_to_actors = AshPaperTrail.Resource.Info.belongs_to_actor(dsl_state)
Expand Down Expand Up @@ -165,7 +166,11 @@ defmodule AshPaperTrail.Resource.Transformers.CreateVersionResource do
end

attributes do
uuid_primary_key(:id)
case unquote(primary_key_type) do
:uuid -> uuid_primary_key :id
:uuid_v7 -> uuid_v7_primary_key :id
:integer -> integer_primary_key :id
end

attribute :version_action_type, :atom do
constraints(one_of: [:create, :update, :destroy])
Expand Down
48 changes: 48 additions & 0 deletions test/ash_paper_trail_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -460,4 +460,52 @@ defmodule AshPaperTrailTest do
Ash.read!(Posts.Post.Version, tenant: "acme")
|> Enum.sort_by(& &1.version_inserted_at)
end

describe ":primary_key_type options" do
test ":id as as UUID" do
assert AshPaperTrail.Resource.Info.primary_key_type(Posts.Post) == :uuid

post = Posts.Post.create!(@valid_attrs, tenant: "acme")
Posts.Post.update!(post, %{subject: "new subject"}, tenant: "acme")

[updated_version] =
Ash.read!(Posts.Post.Version, tenant: "acme")
|> Enum.filter(&(&1.version_action_type == :update))

uuid = updated_version.id
assert {:ok, binary_uuid} = Ash.Type.dump_to_native(Ash.Type.UUID, uuid)
assert {:ok, ^uuid} = Ash.Type.cast_input(Ash.Type.UUID, binary_uuid)
end

test ":id as UUID v7" do
assert AshPaperTrail.Resource.Info.primary_key_type(Accounts.User) == :uuid_v7

user = Accounts.User.create!(%{name: "name"})
Accounts.User.update!(user, %{name: "new name"})

[updated_version] =
Ash.read!(Accounts.User.Version)
|> Enum.filter(&(&1.version_action_type == :update))

uuid_v7 = updated_version.id
assert {:ok, binary_uuid_v7} = Ash.Type.dump_to_native(Ash.Type.UUIDv7, uuid_v7)
assert {:ok, ^uuid_v7} = Ash.Type.cast_input(Ash.Type.UUIDv7, binary_uuid_v7)
end

test ":id as integer" do
assert AshPaperTrail.Resource.Info.primary_key_type(Articles.Article) == :integer

article = Articles.Article.create!("subject", "body")
Articles.Article.update!(article, %{subject: "new subject"})

[updated_version] =
Ash.read!(Articles.Article.Version)
|> Enum.filter(&(&1.version_action_type == :update))

# The id is expected to be generated by the data layer.
# As the ETS data layer used for testing doesn't know how to generate the
# id, we expect `nil` instead.
assert is_nil(updated_version.id)
end
end
end
1 change: 1 addition & 0 deletions test/support/accounts/domain.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule AshPaperTrail.Test.Accounts.Domain do

resources do
resource AshPaperTrail.Test.Accounts.User
resource AshPaperTrail.Test.Accounts.User.Version
resource AshPaperTrail.Test.Accounts.NewsFeed
end
end
8 changes: 7 additions & 1 deletion test/support/accounts/user.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,26 @@ defmodule AshPaperTrail.Test.Accounts.User do
use Ash.Resource,
domain: AshPaperTrail.Test.Accounts.Domain,
data_layer: Ash.DataLayer.Ets,
extensions: [AshPaperTrail.Resource],
validate_domain_inclusion?: false

ets do
private? true
end

paper_trail do
primary_key_type :uuid_v7
end

code_interface do
define :create
define :read
define :update
end

actions do
default_accept [:name]
defaults [:create, :read]
defaults [:create, :read, :update]
end

attributes do
Expand Down
1 change: 1 addition & 0 deletions test/support/articles/article.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ defmodule AshPaperTrail.Test.Articles.Article do
end

paper_trail do
primary_key_type :integer
attributes_as_attributes [:subject, :body]
change_tracking_mode :snapshot
end
Expand Down
1 change: 1 addition & 0 deletions test/support/posts/post.ex
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ defmodule AshPaperTrail.Test.Posts.Post do
end

paper_trail do
primary_key_type :uuid
attributes_as_attributes [:subject, :body, :tenant]
ignore_attributes [:inserted_at]
change_tracking_mode :changes_only
Expand Down

0 comments on commit 6c6d772

Please sign in to comment.