finishing up action tests

This commit is contained in:
Zach Daniel 2019-12-23 23:22:31 -05:00
parent 06e372e029
commit 6702c8eb3a
No known key found for this signature in database
GPG key ID: A57053A671EE649E
5 changed files with 89 additions and 29 deletions

View file

@ -122,3 +122,6 @@ end
* Clean up and test filter inspecting code. * Clean up and test filter inspecting code.
* Handle related values on delete * Handle related values on delete
* Use ashton to validate interface opts, not just document them: Easy and important * Use ashton to validate interface opts, not just document them: Easy and important
* Make an automatic test suite that confirms that data layers behave the way
they claim to behave, maybe.
* Perhaps, reverse relationships should eliminate the need to set destination field.

View file

@ -191,21 +191,25 @@ defmodule Ash.Actions.ChangesetHelpers do
defp many_to_many_assoc_update(changeset, rel, filters, authorize?, user) do defp many_to_many_assoc_update(changeset, rel, filters, authorize?, user) do
changeset changeset
|> before_change(fn %{__ash_api__: api} = changeset -> |> before_change(fn %{__ash_api__: api} = changeset ->
source_field_value = Ecto.Changeset.get_field(changeset, rel.source_field) if changeset.action == :update do
source_field_value = Ecto.Changeset.get_field(changeset, rel.source_field)
destroy_result = destroy_result =
destroy_no_longer_related_join_table_rows( destroy_no_longer_related_join_table_rows(
api, api,
source_field_value, source_field_value,
rel, rel,
filters, filters,
authorize?, authorize?,
user user
) )
case destroy_result do case destroy_result do
:ok -> changeset :ok -> changeset
{:error, error} -> {:error, error} {:error, error} -> {:error, error}
end
else
changeset
end end
end) end)
|> after_change(fn %{__ash_api__: api}, result -> |> after_change(fn %{__ash_api__: api}, result ->

View file

@ -168,6 +168,24 @@ defmodule Ash.Api.Interface do
@callback destroy(record :: Ash.record(), params :: Ash.update_params()) :: @callback destroy(record :: Ash.record(), params :: Ash.update_params()) ::
{:ok, Ash.record()} | {:error, Ash.error()} {:ok, Ash.record()} | {:error, Ash.error()}
@doc """
Refetches a record from the database
"""
@callback reload(record :: Ash.record(), params :: Ash.params()) ::
{:ok, Ash.record()} | {:error, Ash.error()}
@doc """
Refetches a record from the database, raising on error.
See `reload/1`.
"""
@callback reload!(record :: Ash.record(), params :: Ash.params()) :: Ash.record() | no_return
@doc """
Refetches a record from the database
"""
@callback reload(record :: Ash.record()) :: {:ok, Ash.record()} | {:error, Ash.error()}
defmacro __using__(_) do defmacro __using__(_) do
quote do quote do
@behaviour Ash.Api.Interface @behaviour Ash.Api.Interface
@ -236,6 +254,18 @@ defmodule Ash.Api.Interface do
{:error, error} -> {:error, List.wrap(error)} {:error, error} -> {:error, List.wrap(error)}
end end
end end
@impl true
def reload!(%resource{} = record, params \\ []) do
id = record |> Map.take(Ash.primary_key(resource)) |> Enum.to_list()
get!(resource, id, params)
end
@impl true
def reload(%resource{} = record, params \\ []) do
id = record |> Map.take(Ash.primary_key(resource)) |> Enum.to_list()
get(resource, id, params)
end
end end
end end

View file

@ -191,7 +191,7 @@ defmodule Ash.DataLayer.Ets do
end) end)
end end
defp related_ids_filter(%{cardinality: :many_to_many} = rel, filter) do defp related_ids_filter(%{type: :many_to_many} = rel, filter) do
destination_query = %Query{ destination_query = %Query{
resource: rel.destination, resource: rel.destination,
filter: filter filter: filter

View file

@ -16,9 +16,7 @@ defmodule Ash.Test.Filter.FilterTest do
end end
relationships do relationships do
belongs_to :user, Ash.Test.Filter.FilterTest.User, belongs_to :user, Ash.Test.Filter.FilterTest.User
source_field: :user_id,
destination_field: :id
end end
end end
@ -38,11 +36,15 @@ defmodule Ash.Test.Filter.FilterTest do
end end
relationships do relationships do
has_many :posts, Ash.Test.Filter.FilterTest.Post, reverse_relationship: :author1 has_many :posts, Ash.Test.Filter.FilterTest.Post,
reverse_relationship: :author1,
destination_field: :author1_id
has_one :profile, Profile, has_many :second_posts, Ash.Test.Filter.FilterTest.Post,
destination_field: :user_id, reverse_relationship: :author2,
source_field: :id destination_field: :author1_id
has_one :profile, Profile
end end
end end
@ -165,6 +167,12 @@ defmodule Ash.Test.Filter.FilterTest do
relationships: %{related_posts: [post1, post2]} relationships: %{related_posts: [post1, post2]}
) )
post4 =
Api.create!(Post,
attributes: %{title: "title4", contents: "contents3", points: 4},
relationships: %{related_posts: [post3]}
)
profile1 = Api.create!(Profile, attributes: %{bio: "dope"}) profile1 = Api.create!(Profile, attributes: %{bio: "dope"})
user1 = user1 =
@ -178,16 +186,31 @@ defmodule Ash.Test.Filter.FilterTest do
profile2 = Api.create!(Profile, attributes: %{bio: "dope2"}, relationships: %{user: user2}) profile2 = Api.create!(Profile, attributes: %{bio: "dope2"}, relationships: %{user: user2})
%{ %{
post1: post1, post1: Api.reload!(post1),
post2: post2, post2: Api.reload!(post2),
post3: post3, post3: Api.reload!(post3),
profile1: profile1, post4: Api.reload!(post4),
user1: user1, profile1: Api.reload!(profile1),
user2: user2, user1: Api.reload!(user1),
profile2: profile2 user2: Api.reload!(user2),
profile2: Api.reload!(profile2)
} }
end end
test "it works" test "filtering on a has_one relationship", %{profile2: profile2, user2: user2} do
assert %{results: [^user2]} = Api.read!(User, filter: [profile: profile2.id])
end
test "filtering on a belongs_to relationship", %{profile1: profile1, user1: user1} do
assert %{results: [^profile1]} = Api.read!(Profile, filter: [user: user1.id])
end
test "filtering on a has_many relationship", %{user2: user2, post2: post2} do
assert %{results: [^user2]} = Api.read!(User, filter: [posts: post2.id])
end
test "filtering on a many_to_many relationship", %{post4: post4, post3: post3} do
assert %{results: [^post4]} = Api.read!(Post, filter: [related_posts: post3.id])
end
end end
end end