mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 05:23:03 +12:00
WIP, action tests
This commit is contained in:
parent
2c3c368a7e
commit
50941958e6
8 changed files with 435 additions and 319 deletions
|
@ -120,3 +120,4 @@ end
|
|||
is supposed to be optional
|
||||
* relationships updates are *extremely* unoptimized
|
||||
* Clean up and test filter inspecting code.
|
||||
* Handle related values on delete
|
||||
|
|
|
@ -1,43 +1,47 @@
|
|||
defmodule Ash.Actions.ChangesetHelpers do
|
||||
alias Ash.Actions.PrimaryKeyHelpers
|
||||
|
||||
@type before_change_callback :: (Ecto.Changeset.t() -> Ecto.Changeset.t())
|
||||
@type after_change_callback ::
|
||||
(Ecto.Changeset.t(), Ash.record() -> {:ok, Ash.record()} | {:error, Ash.error()})
|
||||
|
||||
@spec before_change(Ecto.Changeset.t(), before_change_callback) :: Ecto.Changeset.t()
|
||||
def before_change(changeset, func) do
|
||||
Map.update(changeset, :__before_ash_changes__, [func], fn funcs ->
|
||||
[func | funcs]
|
||||
end)
|
||||
end
|
||||
|
||||
@spec after_change(Ecto.Changeset.t(), after_change_callback) :: Ecto.Changeset.t()
|
||||
def after_change(changeset, func) do
|
||||
Map.update(changeset, :__after_ash_changes__, [func], fn funcs ->
|
||||
[func | funcs]
|
||||
end)
|
||||
end
|
||||
|
||||
@spec run_before_changes(Ecto.Changeset.t()) :: Ecto.Changeset.t()
|
||||
def run_before_changes(%{__before_ash_changes__: hooks} = changeset) do
|
||||
Enum.reduce(hooks, changeset, fn
|
||||
hook, %Ecto.Changeset{valid?: true} = changeset ->
|
||||
case hook.(changeset) do
|
||||
:ok -> changeset
|
||||
{:ok, changeset} -> changeset
|
||||
%Ecto.Changeset{} = changeset -> changeset
|
||||
end
|
||||
|
||||
_, %Ecto.Changeset{} = changeset ->
|
||||
changeset
|
||||
|
||||
_, {:error, error} ->
|
||||
{:error, error}
|
||||
end)
|
||||
end
|
||||
|
||||
def run_before_changes(changeset), do: changeset
|
||||
|
||||
@spec run_after_changes(Ecto.Changeset.t(), Ash.record()) ::
|
||||
{:ok, Ash.record()} | {:error, Ash.error()}
|
||||
def run_after_changes(%{__after_ash_changes__: hooks} = changeset, result) do
|
||||
Enum.reduce(hooks, {:ok, result}, fn
|
||||
hook, {:ok, result} ->
|
||||
case hook.(changeset, result) do
|
||||
{:ok, result} -> {:ok, result}
|
||||
:ok -> {:ok, result}
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
|
||||
|
@ -50,110 +54,208 @@ defmodule Ash.Actions.ChangesetHelpers do
|
|||
{:ok, result}
|
||||
end
|
||||
|
||||
def belongs_to_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
identifier,
|
||||
@spec prepare_relationship_changes(
|
||||
Ecto.Changeset.t(),
|
||||
Ash.resource(),
|
||||
map(),
|
||||
boolean,
|
||||
Ash.user()
|
||||
) :: Ecto.Changeset.t()
|
||||
def prepare_relationship_changes(
|
||||
changeset,
|
||||
resource,
|
||||
relationships,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
case PrimaryKeyHelpers.value_to_primary_key_filter(destination, identifier) do
|
||||
{:error, _error} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship.name, "Invalid primary key supplied")
|
||||
Enum.reduce(relationships, changeset, fn {relationship, value}, changeset ->
|
||||
with {:rel, rel} when not is_nil(rel) <- {:rel, Ash.relationship(resource, relationship)},
|
||||
{:ok, filter} <- primary_key_filter(rel, value) do
|
||||
case rel.type do
|
||||
:belongs_to ->
|
||||
belongs_to_assoc_update(changeset, rel, filter, authorize?, user)
|
||||
|
||||
{:ok, filter} ->
|
||||
before_change(changeset, fn changeset ->
|
||||
case api.get(destination, filter, authorize?: authorize?, user: user) do
|
||||
{:ok, record} when not is_nil(record) ->
|
||||
changeset
|
||||
|> Ecto.Changeset.put_change(source_field, Map.get(record, destination_field))
|
||||
|> after_change(fn _changeset, result ->
|
||||
{:ok, Map.put(result, relationship.name, record)}
|
||||
end)
|
||||
:has_one ->
|
||||
has_one_assoc_update(changeset, rel, filter, authorize?, user)
|
||||
|
||||
{:ok, nil} ->
|
||||
{:error, "not found"}
|
||||
:has_many ->
|
||||
has_many_assoc_update(changeset, rel, filter, authorize?, user)
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
end)
|
||||
end
|
||||
:many_to_many ->
|
||||
many_to_many_assoc_update(changeset, rel, filter, value, authorize?, user)
|
||||
end
|
||||
else
|
||||
{:rel, nil} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship, "No such relationship")
|
||||
|
||||
{:error, error} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship, error)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
def has_one_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
identifier,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
case PrimaryKeyHelpers.value_to_primary_key_filter(destination, identifier) do
|
||||
{:error, _error} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship.name, "Invalid primary key supplied")
|
||||
|
||||
{:ok, filter} ->
|
||||
after_change(changeset, fn _changeset, result ->
|
||||
value = Map.get(result, source_field)
|
||||
|
||||
with {:ok, record} <-
|
||||
api.get(destination, filter, authorize?: authorize?, user: user),
|
||||
{:ok, updated_record} <-
|
||||
api.update(record, attributes: %{destination_field => value}) do
|
||||
{:ok, Map.put(result, relationship.name, updated_record)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
defp primary_key_filter(%{cardinality: :many, destination: destination}, value) do
|
||||
PrimaryKeyHelpers.values_to_primary_key_filters(destination, value)
|
||||
end
|
||||
|
||||
def many_to_many_assoc_on_create(changeset, %{name: rel_name}, identifier, _, _)
|
||||
when not is_list(identifier) do
|
||||
defp primary_key_filter(%{destination: destination}, value) do
|
||||
PrimaryKeyHelpers.value_to_primary_key_filter(destination, value)
|
||||
end
|
||||
|
||||
defp belongs_to_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
filter,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
before_change(changeset, fn changeset ->
|
||||
case api.get(destination, filter, authorize?: authorize?, user: user) do
|
||||
{:ok, record} when not is_nil(record) ->
|
||||
changeset
|
||||
|> Ecto.Changeset.put_change(source_field, Map.get(record, destination_field))
|
||||
|> after_change(fn _changeset, result ->
|
||||
{:ok, Map.put(result, relationship.name, record)}
|
||||
end)
|
||||
|
||||
{:ok, nil} ->
|
||||
{:error, "not found"}
|
||||
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp has_one_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
filter,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
changeset
|
||||
|> before_change(fn changeset ->
|
||||
value = Map.get(changeset.data, source_field)
|
||||
|
||||
if changeset.action == :update && value do
|
||||
case api.get(destination, [{destination_field, value}]) do
|
||||
{:ok, nil} ->
|
||||
changeset
|
||||
|
||||
{:ok, record} ->
|
||||
case api.update(record, attributes: %{destination_field => nil}) do
|
||||
{:ok, _} ->
|
||||
changeset
|
||||
|
||||
{:error, error} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship.name, error)
|
||||
end
|
||||
|
||||
{:error, error} ->
|
||||
Ecto.Changeset.add_error(
|
||||
changeset,
|
||||
relationship.name,
|
||||
error
|
||||
)
|
||||
end
|
||||
else
|
||||
changeset
|
||||
end
|
||||
end)
|
||||
|> after_change(fn _changeset, result ->
|
||||
value = Map.get(result, source_field)
|
||||
|
||||
with {:ok, record} <-
|
||||
api.get(destination, filter, authorize?: authorize?, user: user),
|
||||
{:ok, updated_record} <-
|
||||
api.update(record, attributes: %{destination_field => value}) do
|
||||
{:ok, Map.put(result, relationship.name, updated_record)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp many_to_many_assoc_update(changeset, %{name: rel_name}, filter, _, _, _)
|
||||
when not is_list(filter) do
|
||||
Ecto.Changeset.add_error(changeset, rel_name, "Invalid value")
|
||||
end
|
||||
|
||||
def many_to_many_assoc_on_create(changeset, rel, identifiers, authorize?, user) do
|
||||
case PrimaryKeyHelpers.values_to_primary_key_filters(rel.destination, identifiers) do
|
||||
{:error, _error} ->
|
||||
Ecto.Changeset.add_error(changeset, rel.name, "Invalid primary key supplied")
|
||||
defp many_to_many_assoc_update(changeset, rel, filters, identifiers, authorize?, user) do
|
||||
changeset
|
||||
|> before_change(fn %{__ash_api__: api} = changeset ->
|
||||
source_field_value = Ecto.Changeset.get_field(changeset, rel.source_field)
|
||||
|
||||
{:ok, filters} ->
|
||||
changeset
|
||||
|> before_change(fn %{__ash_api__: api} = changeset ->
|
||||
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}
|
||||
end
|
||||
end)
|
||||
|> after_change(fn %{__ash_api__: api}, result ->
|
||||
case fetch_and_ensure_related(identifiers, api, result, rel, authorize?, user) do
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
|
||||
case destroy_result do
|
||||
:ok -> changeset
|
||||
{:error, error} -> {:error, error}
|
||||
end
|
||||
end)
|
||||
|> after_change(fn %{__ash_api__: api}, result ->
|
||||
case fetch_and_ensure_related(identifiers, api, result, rel, authorize?, user) do
|
||||
{:error, error} ->
|
||||
{:error, error}
|
||||
{:ok, related} ->
|
||||
{:ok, Map.put(result, rel.name, related)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
{:ok, related} ->
|
||||
{:ok, Map.put(result, rel.name, related)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
defp has_many_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
filters,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
after_change(changeset, fn _changeset, %resource{} = result ->
|
||||
value = Map.get(result, source_field)
|
||||
|
||||
currently_related_filter =
|
||||
result
|
||||
|> Map.take(Ash.primary_key(resource))
|
||||
|> Map.to_list()
|
||||
|
||||
params = [
|
||||
filter: currently_related_filter,
|
||||
paginate?: false,
|
||||
authorize?: authorize?,
|
||||
user: user
|
||||
]
|
||||
|
||||
with {:ok, %{results: related}} <-
|
||||
api.read(destination, params),
|
||||
{:ok, to_relate} <-
|
||||
get_to_relate(api, filters, destination, authorize?, user),
|
||||
to_clear <- get_no_longer_present(resource, related, to_relate),
|
||||
:ok <- clear_related(api, resource, to_clear, destination_field, authorize?, user),
|
||||
{:ok, now_related} <-
|
||||
relate_items(api, to_relate, destination_field, value, authorize?, user) do
|
||||
{:ok, Map.put(result, relationship.name, now_related)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp fetch_and_ensure_related(identifiers, api, %resource{} = result, rel, authorize?, user) do
|
||||
|
@ -276,61 +378,6 @@ defmodule Ash.Actions.ChangesetHelpers do
|
|||
end
|
||||
end
|
||||
|
||||
def many_to_many_assoc_update(changeset, %{name: rel_name}, identifier, _, _)
|
||||
when not is_list(identifier) do
|
||||
Ecto.Changeset.add_error(changeset, rel_name, "Invalid value")
|
||||
end
|
||||
|
||||
def has_many_assoc_update(changeset, %{name: rel_name}, identifier, _, _)
|
||||
when not is_list(identifier) do
|
||||
Ecto.Changeset.add_error(changeset, rel_name, "Invalid value")
|
||||
end
|
||||
|
||||
def has_many_assoc_update(
|
||||
%{__ash_api__: api} = changeset,
|
||||
%{
|
||||
destination: destination,
|
||||
destination_field: destination_field,
|
||||
source_field: source_field
|
||||
} = relationship,
|
||||
identifiers,
|
||||
authorize?,
|
||||
user
|
||||
) do
|
||||
case PrimaryKeyHelpers.values_to_primary_key_filters(destination, identifiers) do
|
||||
{:error, _error} ->
|
||||
Ecto.Changeset.add_error(changeset, relationship.name, "Invalid primary key supplied")
|
||||
|
||||
{:ok, filters} ->
|
||||
after_change(changeset, fn _changeset, %resource{} = result ->
|
||||
value = Map.get(result, source_field)
|
||||
|
||||
currently_related_filter =
|
||||
result
|
||||
|> Map.take(Ash.primary_key(resource))
|
||||
|> Map.to_list()
|
||||
|
||||
params = [
|
||||
filter: currently_related_filter,
|
||||
paginate?: false,
|
||||
authorize?: authorize?,
|
||||
user: user
|
||||
]
|
||||
|
||||
with {:ok, %{results: related}} <-
|
||||
api.read(destination, params),
|
||||
{:ok, to_relate} <-
|
||||
get_to_relate(api, filters, destination, authorize?, user),
|
||||
to_clear <- get_no_longer_present(resource, related, to_relate),
|
||||
:ok <- clear_related(api, resource, to_clear, destination_field, authorize?, user),
|
||||
{:ok, now_related} <-
|
||||
relate_items(api, to_relate, destination_field, value, authorize?, user) do
|
||||
{:ok, Map.put(result, relationship.name, now_related)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
defp relate_items(api, to_relate, _destination_field, destination_field_value, authorize?, user) do
|
||||
Enum.reduce(to_relate, {:ok, []}, fn
|
||||
to_be_related, {:ok, now_related} ->
|
||||
|
|
|
@ -63,11 +63,20 @@ defmodule Ash.Actions.Create do
|
|||
authorize? = Keyword.get(params, :authorize?, false)
|
||||
user = Keyword.get(params, :user)
|
||||
|
||||
with %{valid?: true} = changeset <- prepare_create_attributes(resource, attributes),
|
||||
changeset <- Map.put(changeset, :__ash_api__, api) do
|
||||
prepare_create_relationships(changeset, resource, relationships, authorize?, user)
|
||||
else
|
||||
%{valid?: false} = changeset -> changeset
|
||||
case prepare_create_attributes(resource, attributes) do
|
||||
%{valid?: true} = changeset ->
|
||||
changeset = Map.put(changeset, :__ash_api__, api)
|
||||
|
||||
ChangesetHelpers.prepare_relationship_changes(
|
||||
changeset,
|
||||
resource,
|
||||
relationships,
|
||||
authorize?,
|
||||
user
|
||||
)
|
||||
|
||||
changeset ->
|
||||
changeset
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -92,30 +101,10 @@ defmodule Ash.Actions.Create do
|
|||
resource
|
||||
|> struct()
|
||||
|> Ecto.Changeset.cast(attributes_with_defaults, allowed_keys)
|
||||
|> Map.put(:action, :create)
|
||||
end
|
||||
|
||||
defp default(%{default: {:constant, value}}), do: value
|
||||
defp default(%{default: {mod, func}}), do: apply(mod, func, [])
|
||||
defp default(%{default: function}), do: function.()
|
||||
|
||||
defp prepare_create_relationships(changeset, resource, relationships, authorize?, user) do
|
||||
Enum.reduce(relationships, changeset, fn {relationship, value}, changeset ->
|
||||
case Ash.relationship(resource, relationship) do
|
||||
%{type: :belongs_to} = rel ->
|
||||
ChangesetHelpers.belongs_to_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
%{type: :has_one} = rel ->
|
||||
ChangesetHelpers.has_one_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
%{type: :has_many} = rel ->
|
||||
ChangesetHelpers.has_many_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
%{type: :many_to_many} = rel ->
|
||||
ChangesetHelpers.many_to_many_assoc_on_create(changeset, rel, value, authorize?, user)
|
||||
|
||||
_ ->
|
||||
Ecto.Changeset.add_error(changeset, relationship, "No such relationship")
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -74,7 +74,13 @@ defmodule Ash.Actions.Update do
|
|||
|
||||
with %{valid?: true} = changeset <- prepare_update_attributes(record, attributes),
|
||||
changeset <- Map.put(changeset, :__ash_api__, api) do
|
||||
prepare_update_relationships(changeset, resource, relationships, authorize?, user)
|
||||
ChangesetHelpers.prepare_relationship_changes(
|
||||
changeset,
|
||||
resource,
|
||||
relationships,
|
||||
authorize?,
|
||||
user
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,27 +90,8 @@ defmodule Ash.Actions.Update do
|
|||
|> Ash.attributes()
|
||||
|> Enum.map(& &1.name)
|
||||
|
||||
Ecto.Changeset.cast(record, attributes, allowed_keys)
|
||||
end
|
||||
|
||||
defp prepare_update_relationships(changeset, resource, relationships, authorize?, user) do
|
||||
Enum.reduce(relationships, changeset, fn {relationship, value}, changeset ->
|
||||
case Ash.relationship(resource, relationship) do
|
||||
%{type: :belongs_to} = rel ->
|
||||
ChangesetHelpers.belongs_to_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
%{type: :has_one} = rel ->
|
||||
ChangesetHelpers.has_one_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
%{type: :has_many} = rel ->
|
||||
ChangesetHelpers.has_many_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
# %{type: :many_to_many} = rel ->
|
||||
# ChangesetHelpers.many_to_many_assoc_update(changeset, rel, value, authorize?, user)
|
||||
|
||||
_ ->
|
||||
Ecto.Changeset.add_error(changeset, relationship, "No such relationship")
|
||||
end
|
||||
end)
|
||||
record
|
||||
|> Ecto.Changeset.cast(attributes, allowed_keys)
|
||||
|> Map.put(:action, :update)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -63,7 +63,7 @@ defmodule Ash.Api.Interface do
|
|||
|
||||
@spec destroy(Ash.record(), Ash.update_params()) ::
|
||||
{:ok, Ash.record()} | {:error, Ash.error()}
|
||||
def destory(record, params \\ []) do
|
||||
def destroy(record, params \\ []) do
|
||||
case Ash.Api.Interface.destroy(__MODULE__, record, params) do
|
||||
{:ok, instance} -> {:ok, instance}
|
||||
{:error, error} -> {:error, List.wrap(error)}
|
||||
|
@ -231,7 +231,8 @@ defmodule Ash.Api.Interface do
|
|||
raise Ash.Error.FrameworkError.exception(message: error)
|
||||
end
|
||||
|
||||
defp unwrap_or_raise!({:error, %Ecto.Changeset{}}) do
|
||||
defp unwrap_or_raise!({:error, %Ecto.Changeset{} = cs}) do
|
||||
IO.inspect(cs)
|
||||
raise(Ash.Error.FrameworkError, message: "invalid changes")
|
||||
end
|
||||
|
||||
|
@ -248,8 +249,9 @@ defmodule Ash.Api.Interface do
|
|||
string when is_bitstring(string) ->
|
||||
Ash.Error.FrameworkError.exception(message: string)
|
||||
|
||||
_ = %Ecto.Changeset{} ->
|
||||
_ = %Ecto.Changeset{} = cs ->
|
||||
# TODO: format these
|
||||
IO.inspect(cs)
|
||||
"invalid changes"
|
||||
|
||||
error ->
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
defmodule Ash.Authorization.Checks do
|
||||
@moduledoc "Built in authorization checks."
|
||||
|
||||
def always(), do: [__always__: true]
|
||||
def always() do
|
||||
[always: true]
|
||||
end
|
||||
|
||||
def related_to_user_via(relationship) do
|
||||
relationship
|
||||
|> List.wrap()
|
||||
|> put_nested_relationship()
|
||||
filter =
|
||||
relationship
|
||||
|> List.wrap()
|
||||
|> put_nested_relationship()
|
||||
|
||||
[filter: filter]
|
||||
end
|
||||
|
||||
defp put_nested_relationship([rel | rest]) do
|
||||
|
|
|
@ -87,120 +87,4 @@ defmodule Ash.Test.Actions.DestroyTest do
|
|||
refute Api.get!(Post, post.id)
|
||||
end
|
||||
end
|
||||
|
||||
# describe "simple creates" do
|
||||
# test "allows creating a record with valid attributes" do
|
||||
# assert %Post{title: "foo", contents: "bar"} =
|
||||
# Api.create!(Post, attributes: %{title: "foo", contents: "bar"})
|
||||
# end
|
||||
|
||||
# test "constant default values are set properly" do
|
||||
# assert %Post{tag: "garbage"} = Api.create!(Post, attributes: %{title: "foo"})
|
||||
# end
|
||||
|
||||
# test "constant functions values are set properly" do
|
||||
# assert %Post{tag2: "garbage2"} = Api.create!(Post, attributes: %{title: "foo"})
|
||||
# end
|
||||
|
||||
# test "constant module/function values are set properly" do
|
||||
# assert %Post{tag3: "garbage3"} = Api.create!(Post, attributes: %{title: "foo"})
|
||||
# end
|
||||
# end
|
||||
|
||||
# describe "creating with has_one relationships" do
|
||||
# test "allows creating with has_one relationship" do
|
||||
# profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
|
||||
# Api.create!(Author,
|
||||
# attributes: %{name: "fred"},
|
||||
# relationships: %{profile: profile.id}
|
||||
# )
|
||||
# end
|
||||
|
||||
# test "it sets the relationship on the destination record accordingly" do
|
||||
# profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
|
||||
# author =
|
||||
# Api.create!(Author,
|
||||
# attributes: %{name: "fred"},
|
||||
# relationships: %{profile: profile.id}
|
||||
# )
|
||||
|
||||
# assert Api.get!(Profile, profile.id).author_id == author.id
|
||||
# end
|
||||
|
||||
# test "it responds with the relationshi filled in" do
|
||||
# profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
|
||||
# author =
|
||||
# Api.create!(Author,
|
||||
# attributes: %{name: "fred"},
|
||||
# relationships: %{profile: profile.id}
|
||||
# )
|
||||
|
||||
# assert author.profile == Map.put(profile, :author_id, author.id)
|
||||
# end
|
||||
# end
|
||||
|
||||
# describe "creating with a has_many relationship" do
|
||||
# test "allows creating with a has_many relationship" do
|
||||
# post = Api.create!(Post, attributes: %{title: "sup"})
|
||||
|
||||
# Api.create!(Author,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# posts: [post.id]
|
||||
# }
|
||||
# )
|
||||
# end
|
||||
# end
|
||||
|
||||
# describe "creating with belongs_to relationships" do
|
||||
# test "allows creating with belongs_to relationship" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# )
|
||||
# end
|
||||
|
||||
# test "it sets the relationship on the destination record accordingly" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# post =
|
||||
# Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# )
|
||||
|
||||
# assert Api.get!(Post, post.id).author_id == author.id
|
||||
# end
|
||||
|
||||
# test "it responds with the relationship field filled in" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# assert Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# ).author_id == author.id
|
||||
# end
|
||||
|
||||
# test "it responds with the relationship filled in" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# assert Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# ).author == author
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
|
201
test/actions/update_test.exs
Normal file
201
test/actions/update_test.exs
Normal file
|
@ -0,0 +1,201 @@
|
|||
defmodule Ash.Test.Actions.UpdateTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
defmodule Profile do
|
||||
use Ash.Resource, name: "authors", type: "author"
|
||||
use Ash.DataLayer.Ets, private?: true
|
||||
|
||||
actions do
|
||||
read :default
|
||||
create :default
|
||||
update :default
|
||||
end
|
||||
|
||||
attributes do
|
||||
attribute :bio, :string
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :author, Ash.Test.Actions.UpdateTest.Author
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Author do
|
||||
use Ash.Resource, name: "authors", type: "author"
|
||||
use Ash.DataLayer.Ets, private?: true
|
||||
|
||||
actions do
|
||||
read :default
|
||||
create :default
|
||||
update :default
|
||||
end
|
||||
|
||||
attributes do
|
||||
attribute :name, :string
|
||||
end
|
||||
|
||||
relationships do
|
||||
has_one :profile, Profile
|
||||
|
||||
has_many :posts, Ash.Test.Actions.UpdateTest.Post
|
||||
end
|
||||
end
|
||||
|
||||
defmodule PostDefaults do
|
||||
def garbage2(), do: "garbage2"
|
||||
def garbage3(), do: "garbage3"
|
||||
end
|
||||
|
||||
defmodule Post do
|
||||
use Ash.Resource, name: "posts", type: "post"
|
||||
use Ash.DataLayer.Ets, private?: true
|
||||
|
||||
actions do
|
||||
read :default
|
||||
create :default
|
||||
update :default
|
||||
end
|
||||
|
||||
attributes do
|
||||
attribute :title, :string
|
||||
attribute :contents, :string
|
||||
attribute :tag, :string, default: {:constant, "garbage"}
|
||||
attribute :tag2, :string, default: &PostDefaults.garbage2/0
|
||||
attribute :tag3, :string, default: {PostDefaults, :garbage3}
|
||||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :author, Author
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Api do
|
||||
use Ash.Api
|
||||
|
||||
resources [Author, Post, Profile]
|
||||
end
|
||||
|
||||
describe "simple updates" do
|
||||
test "allows updating a record with valid attributes" do
|
||||
post = Api.create!(Post, attributes: %{title: "foo", contents: "bar"})
|
||||
|
||||
assert %Post{title: "bar", contents: "foo"} =
|
||||
Api.update!(post, attributes: %{title: "bar", contents: "foo"})
|
||||
end
|
||||
end
|
||||
|
||||
describe "updating with has_one relationships" do
|
||||
test "allows creating with has_one relationship" do
|
||||
profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
profile2 = Api.create!(Profile, attributes: %{bio: "second best dude"})
|
||||
|
||||
author =
|
||||
Api.create!(Author,
|
||||
attributes: %{name: "fred"},
|
||||
relationships: %{profile: profile.id}
|
||||
)
|
||||
|
||||
Api.update!(author, relationships: %{profile: profile2.id})
|
||||
end
|
||||
|
||||
test "it sets the relationship on the destination record accordingly" do
|
||||
profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
profile2 = Api.create!(Profile, attributes: %{bio: "second best dude"})
|
||||
|
||||
author =
|
||||
Api.create!(Author,
|
||||
attributes: %{name: "fred"},
|
||||
relationships: %{profile: profile.id}
|
||||
)
|
||||
|
||||
Api.update!(author, relationships: %{profile: profile2.id})
|
||||
|
||||
assert Api.get!(Profile, profile.id).author_id == nil
|
||||
assert Api.get!(Profile, profile2.id).author_id == author.id
|
||||
end
|
||||
|
||||
test "it responds with the relationship filled in" do
|
||||
profile = Api.create!(Profile, attributes: %{bio: "best dude"})
|
||||
profile2 = Api.create!(Profile, attributes: %{bio: "second best dude"})
|
||||
|
||||
author =
|
||||
Api.create!(Author,
|
||||
attributes: %{name: "fred"},
|
||||
relationships: %{profile: profile.id}
|
||||
)
|
||||
|
||||
updated_author = Api.update!(author, relationships: %{profile: profile2.id})
|
||||
assert updated_author.profile == %{profile2 | author_id: author.id}
|
||||
end
|
||||
end
|
||||
|
||||
describe "updating with a has_many relationship" do
|
||||
test "allows updating with a has_many relationship" do
|
||||
post = Api.create!(Post, attributes: %{title: "sup"})
|
||||
post2 = Api.create!(Post, attributes: %{title: "sup2"})
|
||||
|
||||
author =
|
||||
Api.create!(Author,
|
||||
attributes: %{title: "foobar"},
|
||||
relationships: %{
|
||||
posts: [post.id]
|
||||
}
|
||||
)
|
||||
|
||||
Api.update!(author,
|
||||
relationships: %{
|
||||
posts: [post.id, post2.id]
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# describe "creating with belongs_to relationships" do
|
||||
# test "allows creating with belongs_to relationship" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# )
|
||||
# end
|
||||
|
||||
# test "it sets the relationship on the destination record accordingly" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# post =
|
||||
# Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# )
|
||||
|
||||
# assert Api.get!(Post, post.id).author_id == author.id
|
||||
# end
|
||||
|
||||
# test "it responds with the relationship field filled in" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# assert Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# ).author_id == author.id
|
||||
# end
|
||||
|
||||
# test "it responds with the relationship filled in" do
|
||||
# author = Api.create!(Author, attributes: %{bio: "best dude"})
|
||||
|
||||
# assert Api.create!(Post,
|
||||
# attributes: %{title: "foobar"},
|
||||
# relationships: %{
|
||||
# author: author.id
|
||||
# }
|
||||
# ).author == author
|
||||
# end
|
||||
# end
|
||||
end
|
Loading…
Reference in a new issue