mirror of
https://github.com/ash-project/ash.git
synced 2024-09-20 13:33:20 +12:00
fix: more improvements to resource matching in can?
This commit is contained in:
parent
51db6c5b1a
commit
8927460f77
2 changed files with 125 additions and 58 deletions
174
lib/ash/can.ex
174
lib/ash/can.ex
|
@ -23,45 +23,31 @@ defmodule Ash.Can do
|
||||||
opts = Keyword.put_new(opts, :filter_with, :filter)
|
opts = Keyword.put_new(opts, :filter_with, :filter)
|
||||||
|
|
||||||
{resource, action_or_query_or_changeset, input} =
|
{resource, action_or_query_or_changeset, input} =
|
||||||
case action_or_query_or_changeset do
|
resource_subject_input(action_or_query_or_changeset, domain, opts)
|
||||||
%Ash.Query{} = query ->
|
|
||||||
{query.resource, query, nil}
|
|
||||||
|
|
||||||
%Ash.Changeset{} = changeset ->
|
|
||||||
{changeset.resource, changeset, nil}
|
|
||||||
|
|
||||||
%Ash.ActionInput{} = input ->
|
|
||||||
{input.resource, input, nil}
|
|
||||||
|
|
||||||
{resource, %struct{}} = action
|
|
||||||
when struct in [
|
|
||||||
Ash.Resource.Actions.Create,
|
|
||||||
Ash.Resource.Actions.Read,
|
|
||||||
Ash.Resource.Actions.Update,
|
|
||||||
Ash.Resource.Actions.Destroy,
|
|
||||||
Ash.Resource.Actions.Action
|
|
||||||
] ->
|
|
||||||
{resource, action, %{}}
|
|
||||||
|
|
||||||
{resource, name} when is_atom(name) ->
|
|
||||||
{resource, Ash.Resource.Info.action(resource, name), %{}}
|
|
||||||
|
|
||||||
{resource, %struct{}, input} = action
|
|
||||||
when struct in [
|
|
||||||
Ash.Resource.Actions.Create,
|
|
||||||
Ash.Resource.Actions.Read,
|
|
||||||
Ash.Resource.Actions.Update,
|
|
||||||
Ash.Resource.Actions.Destroy,
|
|
||||||
Ash.Resource.Actions.Action
|
|
||||||
] ->
|
|
||||||
{resource, action, input}
|
|
||||||
|
|
||||||
{resource, name, input} when is_atom(name) ->
|
|
||||||
{resource, Ash.Resource.Info.action(resource, name), input}
|
|
||||||
end
|
|
||||||
|
|
||||||
subject =
|
subject =
|
||||||
case action_or_query_or_changeset do
|
case action_or_query_or_changeset do
|
||||||
|
%Ash.ActionInput{} = action_input ->
|
||||||
|
if opts[:tenant] do
|
||||||
|
Ash.ActionInput.set_tenant(action_input, opts[:tenant])
|
||||||
|
else
|
||||||
|
action_input
|
||||||
|
end
|
||||||
|
|
||||||
|
%Ash.Query{} = query ->
|
||||||
|
if opts[:tenant] do
|
||||||
|
Ash.Query.set_tenant(query, opts[:tenant])
|
||||||
|
else
|
||||||
|
query
|
||||||
|
end
|
||||||
|
|
||||||
|
%Ash.Changeset{} = changeset ->
|
||||||
|
if opts[:tenant] do
|
||||||
|
Ash.Changeset.set_tenant(changeset, opts[:tenant])
|
||||||
|
else
|
||||||
|
changeset
|
||||||
|
end
|
||||||
|
|
||||||
%{type: :update, name: name} ->
|
%{type: :update, name: name} ->
|
||||||
if opts[:data] do
|
if opts[:data] do
|
||||||
Ash.Changeset.for_update(opts[:data], name, input,
|
Ash.Changeset.for_update(opts[:data], name, input,
|
||||||
|
@ -95,23 +81,6 @@ defmodule Ash.Can do
|
||||||
%{type: :action, name: name} ->
|
%{type: :action, name: name} ->
|
||||||
Ash.ActionInput.for_action(resource, name, input, actor: actor)
|
Ash.ActionInput.for_action(resource, name, input, actor: actor)
|
||||||
|
|
||||||
%Ash.ActionInput{} = action_input ->
|
|
||||||
action_input
|
|
||||||
|
|
||||||
%Ash.Query{} = query ->
|
|
||||||
if opts[:tenant] do
|
|
||||||
Ash.Query.set_tenant(query, opts[:tenant])
|
|
||||||
else
|
|
||||||
query
|
|
||||||
end
|
|
||||||
|
|
||||||
%Ash.Changeset{} = changeset ->
|
|
||||||
if opts[:tenant] do
|
|
||||||
Ash.Changeset.set_tenant(changeset, opts[:tenant])
|
|
||||||
else
|
|
||||||
changeset
|
|
||||||
end
|
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
raise ArgumentError,
|
raise ArgumentError,
|
||||||
message: "Invalid action/query/changeset \"#{inspect(action_or_query_or_changeset)}\""
|
message: "Invalid action/query/changeset \"#{inspect(action_or_query_or_changeset)}\""
|
||||||
|
@ -130,6 +99,105 @@ defmodule Ash.Can do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp resource_subject_input(action_or_query_or_changeset, domain, opts) do
|
||||||
|
case action_or_query_or_changeset do
|
||||||
|
{resource, name} when is_atom(name) and is_atom(resource) ->
|
||||||
|
resource_subject_input(
|
||||||
|
{resource, Ash.Resource.Info.action(resource, name), %{}},
|
||||||
|
domain,
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
|
||||||
|
{resource, name, input} when is_atom(name) and is_atom(resource) ->
|
||||||
|
resource_subject_input(
|
||||||
|
{resource, Ash.Resource.Info.action(resource, name), input},
|
||||||
|
domain,
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
|
||||||
|
{%resource{} = record, name} when is_atom(name) and is_atom(resource) ->
|
||||||
|
resource_subject_input(
|
||||||
|
{record, Ash.Resource.Info.action(resource, name), %{}},
|
||||||
|
domain,
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
|
||||||
|
{%resource{} = record, name, input} when is_atom(name) and is_atom(resource) ->
|
||||||
|
resource_subject_input(
|
||||||
|
{record, Ash.Resource.Info.action(resource, name), input},
|
||||||
|
domain,
|
||||||
|
opts
|
||||||
|
)
|
||||||
|
|
||||||
|
%Ash.Query{} = query ->
|
||||||
|
{query.resource, query, nil}
|
||||||
|
|
||||||
|
%Ash.Changeset{} = changeset ->
|
||||||
|
{changeset.resource, changeset, nil}
|
||||||
|
|
||||||
|
%Ash.ActionInput{} = input ->
|
||||||
|
{input.resource, input, nil}
|
||||||
|
|
||||||
|
{resource, %struct{} = action}
|
||||||
|
when struct in [
|
||||||
|
Ash.Resource.Actions.Create,
|
||||||
|
Ash.Resource.Actions.Read,
|
||||||
|
Ash.Resource.Actions.Update,
|
||||||
|
Ash.Resource.Actions.Destroy,
|
||||||
|
Ash.Resource.Actions.Action
|
||||||
|
] ->
|
||||||
|
resource_subject_input({resource, action, %{}}, domain, opts)
|
||||||
|
|
||||||
|
{%resource{} = record, %Ash.Resource.Actions.Read{} = action, input} ->
|
||||||
|
{resource, Ash.Query.for_read(resource, action.name, input) |> filter_by_pkey(record),
|
||||||
|
input}
|
||||||
|
|
||||||
|
{%resource{}, %Ash.Resource.Actions.Action{} = action, input} ->
|
||||||
|
{resource, Ash.ActionInput.for_action(resource, action.name, input), input}
|
||||||
|
|
||||||
|
{%resource{}, %Ash.Resource.Actions.Create{} = action, input} ->
|
||||||
|
{resource, Ash.Changeset.for_create(resource, action.name, input), input}
|
||||||
|
|
||||||
|
{%resource{} = record, %struct{} = action, input}
|
||||||
|
when struct in [
|
||||||
|
Ash.Resource.Actions.Update,
|
||||||
|
Ash.Resource.Actions.Destroy
|
||||||
|
] ->
|
||||||
|
{resource, Ash.Changeset.for_action(record, action.name, input, domain: domain), input}
|
||||||
|
|
||||||
|
{resource, %Ash.Resource.Actions.Read{} = action, input} ->
|
||||||
|
{resource, Ash.Query.for_read(resource, action.name, input, domain: domain), input}
|
||||||
|
|
||||||
|
{resource, %Ash.Resource.Actions.Action{} = action, input} ->
|
||||||
|
{resource, Ash.ActionInput.for_action(resource, action.name, input, domain: domain),
|
||||||
|
input}
|
||||||
|
|
||||||
|
{resource, %Ash.Resource.Actions.Create{} = action, input} ->
|
||||||
|
{resource, Ash.Changeset.for_create(resource, action.name, input, domain: domain), input}
|
||||||
|
|
||||||
|
{resource, %struct{} = action, input}
|
||||||
|
when struct in [
|
||||||
|
Ash.Resource.Actions.Update,
|
||||||
|
Ash.Resource.Actions.Destroy
|
||||||
|
] ->
|
||||||
|
{resource, action, input}
|
||||||
|
|
||||||
|
{resource, action} ->
|
||||||
|
raise ArgumentError, """
|
||||||
|
If providing an update or destroy action, you must provide a record to update or destroy.
|
||||||
|
|
||||||
|
Got: #{inspect({resource, action})}
|
||||||
|
"""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp filter_by_pkey(query, %resource{} = record) do
|
||||||
|
Ash.Query.do_filter(
|
||||||
|
query,
|
||||||
|
record |> Map.take(Ash.Resource.Info.primary_key(resource)) |> Map.to_list()
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defp alter_source({:ok, true, query}, domain, actor, %Ash.Changeset{} = subject, opts) do
|
defp alter_source({:ok, true, query}, domain, actor, %Ash.Changeset{} = subject, opts) do
|
||||||
case alter_source({:ok, true}, domain, actor, subject, Keyword.put(opts, :base_query, query)) do
|
case alter_source({:ok, true}, domain, actor, subject, Keyword.put(opts, :base_query, query)) do
|
||||||
{:ok, true, new_subject} -> {:ok, true, new_subject, query}
|
{:ok, true, new_subject} -> {:ok, true, new_subject, query}
|
||||||
|
|
9
mix.exs
9
mix.exs
|
@ -84,7 +84,7 @@ defmodule Ash.MixProject do
|
||||||
"documentation/topics/store-context-in-process.md",
|
"documentation/topics/store-context-in-process.md",
|
||||||
"documentation/topics/testing.md",
|
"documentation/topics/testing.md",
|
||||||
"documentation/topics/timeouts.md",
|
"documentation/topics/timeouts.md",
|
||||||
"documentation/topics/validations.md",
|
"documentation/topics/validations.md"
|
||||||
],
|
],
|
||||||
groups_for_extras: [
|
groups_for_extras: [
|
||||||
"Start Here": [
|
"Start Here": [
|
||||||
|
@ -99,8 +99,7 @@ defmodule Ash.MixProject do
|
||||||
"documentation/topics/contributing-to-ash.md",
|
"documentation/topics/contributing-to-ash.md",
|
||||||
"CHANGELOG.md"
|
"CHANGELOG.md"
|
||||||
],
|
],
|
||||||
"How To": [
|
"How To": [],
|
||||||
],
|
|
||||||
"DSL Reference": [
|
"DSL Reference": [
|
||||||
"documentation/dsls/DSL:-Ash.Resource.md",
|
"documentation/dsls/DSL:-Ash.Resource.md",
|
||||||
"documentation/dsls/DSL:-Ash.Domain.md",
|
"documentation/dsls/DSL:-Ash.Domain.md",
|
||||||
|
@ -109,7 +108,7 @@ defmodule Ash.MixProject do
|
||||||
"documentation/dsls/DSL:-Ash.DataLayer.Ets.md",
|
"documentation/dsls/DSL:-Ash.DataLayer.Ets.md",
|
||||||
"documentation/dsls/DSL:-Ash.DataLayer.Mnesia.md",
|
"documentation/dsls/DSL:-Ash.DataLayer.Mnesia.md",
|
||||||
"documentation/dsls/DSL:-Ash.Reactor.md",
|
"documentation/dsls/DSL:-Ash.Reactor.md",
|
||||||
"documentation/dsls/DSL:-Ash.DataLayer.Mnesia.md",
|
"documentation/dsls/DSL:-Ash.DataLayer.Mnesia.md"
|
||||||
],
|
],
|
||||||
"Under Review": [
|
"Under Review": [
|
||||||
# Documentation below this line is pending review
|
# Documentation below this line is pending review
|
||||||
|
@ -150,7 +149,7 @@ defmodule Ash.MixProject do
|
||||||
"documentation/topics/store-context-in-process.md",
|
"documentation/topics/store-context-in-process.md",
|
||||||
"documentation/topics/testing.md",
|
"documentation/topics/testing.md",
|
||||||
"documentation/topics/timeouts.md",
|
"documentation/topics/timeouts.md",
|
||||||
"documentation/topics/validations.md",
|
"documentation/topics/validations.md"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
skip_undefined_reference_warnings_on: [
|
skip_undefined_reference_warnings_on: [
|
||||||
|
|
Loading…
Reference in a new issue