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.
* Handle related values on delete
* 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
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_no_longer_related_join_table_rows(
api,
source_field_value,
rel,
filters,
authorize?,
user
)
destroy_result =
destroy_no_longer_related_join_table_rows(
api,
source_field_value,
rel,
filters,
authorize?,
user
)
case destroy_result do
:ok -> changeset
{:error, error} -> {:error, error}
case destroy_result do
:ok -> changeset
{:error, error} -> {:error, error}
end
else
changeset
end
end)
|> 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()) ::
{: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
quote do
@behaviour Ash.Api.Interface
@ -236,6 +254,18 @@ defmodule Ash.Api.Interface do
{:error, error} -> {:error, List.wrap(error)}
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

View file

@ -191,7 +191,7 @@ defmodule Ash.DataLayer.Ets do
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{
resource: rel.destination,
filter: filter

View file

@ -16,9 +16,7 @@ defmodule Ash.Test.Filter.FilterTest do
end
relationships do
belongs_to :user, Ash.Test.Filter.FilterTest.User,
source_field: :user_id,
destination_field: :id
belongs_to :user, Ash.Test.Filter.FilterTest.User
end
end
@ -38,11 +36,15 @@ defmodule Ash.Test.Filter.FilterTest do
end
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,
destination_field: :user_id,
source_field: :id
has_many :second_posts, Ash.Test.Filter.FilterTest.Post,
reverse_relationship: :author2,
destination_field: :author1_id
has_one :profile, Profile
end
end
@ -165,6 +167,12 @@ defmodule Ash.Test.Filter.FilterTest do
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"})
user1 =
@ -178,16 +186,31 @@ defmodule Ash.Test.Filter.FilterTest do
profile2 = Api.create!(Profile, attributes: %{bio: "dope2"}, relationships: %{user: user2})
%{
post1: post1,
post2: post2,
post3: post3,
profile1: profile1,
user1: user1,
user2: user2,
profile2: profile2
post1: Api.reload!(post1),
post2: Api.reload!(post2),
post3: Api.reload!(post3),
post4: Api.reload!(post4),
profile1: Api.reload!(profile1),
user1: Api.reload!(user1),
user2: Api.reload!(user2),
profile2: Api.reload!(profile2)
}
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