mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 21:13:10 +12:00
fix: properly pass actor when running filters at runtime
fix: misplaced curly bracket when handling struct type casting
This commit is contained in:
parent
ec12332e95
commit
b6e1e80fc2
12 changed files with 211 additions and 81 deletions
|
@ -67,10 +67,12 @@ defmodule Ash.Actions.Destroy.Bulk do
|
||||||
opts
|
opts
|
||||||
end
|
end
|
||||||
|
|
||||||
query =
|
{query, opts} =
|
||||||
if query.__validated_for_action__ do
|
if query.__validated_for_action__ do
|
||||||
query
|
{query, opts}
|
||||||
else
|
else
|
||||||
|
{query, opts} = Ash.Actions.Helpers.set_context_and_get_opts(domain, query, opts)
|
||||||
|
|
||||||
query =
|
query =
|
||||||
Ash.Query.for_read(
|
Ash.Query.for_read(
|
||||||
query,
|
query,
|
||||||
|
@ -80,9 +82,7 @@ defmodule Ash.Actions.Destroy.Bulk do
|
||||||
tenant: opts[:tenant]
|
tenant: opts[:tenant]
|
||||||
)
|
)
|
||||||
|
|
||||||
{query, _opts} = Ash.Actions.Helpers.set_context_and_get_opts(domain, query, opts)
|
{query, opts}
|
||||||
|
|
||||||
query
|
|
||||||
end
|
end
|
||||||
|
|
||||||
query = %{query | domain: domain}
|
query = %{query | domain: domain}
|
||||||
|
|
|
@ -999,7 +999,9 @@ defmodule Ash.Actions.Read.Relationships do
|
||||||
case Ash.Filter.Runtime.filter_matches(
|
case Ash.Filter.Runtime.filter_matches(
|
||||||
related_query.domain,
|
related_query.domain,
|
||||||
value,
|
value,
|
||||||
query.filter
|
query.filter,
|
||||||
|
tenant: query.tenant,
|
||||||
|
actor: query.actor
|
||||||
) do
|
) do
|
||||||
{:ok, value} ->
|
{:ok, value} ->
|
||||||
value
|
value
|
||||||
|
|
|
@ -22,10 +22,12 @@ defmodule Ash.Actions.Update.Bulk do
|
||||||
opts
|
opts
|
||||||
end
|
end
|
||||||
|
|
||||||
query =
|
{query, opts} =
|
||||||
if query.__validated_for_action__ do
|
if query.__validated_for_action__ do
|
||||||
query
|
{query, opts}
|
||||||
else
|
else
|
||||||
|
{query, opts} = Ash.Actions.Helpers.set_context_and_get_opts(domain, query, opts)
|
||||||
|
|
||||||
query =
|
query =
|
||||||
Ash.Query.for_read(
|
Ash.Query.for_read(
|
||||||
query,
|
query,
|
||||||
|
@ -35,9 +37,7 @@ defmodule Ash.Actions.Update.Bulk do
|
||||||
tenant: opts[:tenant]
|
tenant: opts[:tenant]
|
||||||
)
|
)
|
||||||
|
|
||||||
{query, _opts} = Ash.Actions.Helpers.set_context_and_get_opts(domain, query, opts)
|
{query, opts}
|
||||||
|
|
||||||
query
|
|
||||||
end
|
end
|
||||||
|
|
||||||
query = %{query | domain: domain}
|
query = %{query | domain: domain}
|
||||||
|
|
|
@ -339,7 +339,12 @@ defmodule Ash.DataLayer.Ets do
|
||||||
},
|
},
|
||||||
{:ok, acc} ->
|
{:ok, acc} ->
|
||||||
results
|
results
|
||||||
|> filter_matches(Map.get(query || %{}, :filter), domain, context[:tenant])
|
|> filter_matches(
|
||||||
|
Map.get(query || %{}, :filter),
|
||||||
|
domain,
|
||||||
|
context[:tenant],
|
||||||
|
context[:actor]
|
||||||
|
)
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, matches} ->
|
{:ok, matches} ->
|
||||||
field = field || Enum.at(Ash.Resource.Info.primary_key(resource), 0)
|
field = field || Enum.at(Ash.Resource.Info.primary_key(resource), 0)
|
||||||
|
@ -386,7 +391,14 @@ defmodule Ash.DataLayer.Ets do
|
||||||
) do
|
) do
|
||||||
with {:ok, records} <- get_records(resource, tenant),
|
with {:ok, records} <- get_records(resource, tenant),
|
||||||
{:ok, records} <-
|
{:ok, records} <-
|
||||||
filter_matches(records, filter, domain, context[:private][:tenant], parent),
|
filter_matches(
|
||||||
|
records,
|
||||||
|
filter,
|
||||||
|
domain,
|
||||||
|
context[:private][:tenant],
|
||||||
|
context[:private][:actor],
|
||||||
|
parent
|
||||||
|
),
|
||||||
records <- Sort.runtime_sort(records, distinct_sort || sort, domain: domain),
|
records <- Sort.runtime_sort(records, distinct_sort || sort, domain: domain),
|
||||||
records <- Sort.runtime_distinct(records, distinct, domain: domain),
|
records <- Sort.runtime_distinct(records, distinct, domain: domain),
|
||||||
records <- Sort.runtime_sort(records, sort, domain: domain),
|
records <- Sort.runtime_sort(records, sort, domain: domain),
|
||||||
|
@ -625,7 +637,9 @@ defmodule Ash.DataLayer.Ets do
|
||||||
case Ash.Expr.eval_hydrated(expression,
|
case Ash.Expr.eval_hydrated(expression,
|
||||||
record: record,
|
record: record,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
domain: domain
|
domain: domain,
|
||||||
|
actor: calculation.context.actor,
|
||||||
|
tenant: calculation.context.tenant
|
||||||
) do
|
) do
|
||||||
{:ok, value} ->
|
{:ok, value} ->
|
||||||
if calculation.load do
|
if calculation.load do
|
||||||
|
@ -722,7 +736,13 @@ defmodule Ash.DataLayer.Ets do
|
||||||
domain
|
domain
|
||||||
),
|
),
|
||||||
{:ok, filtered} <-
|
{:ok, filtered} <-
|
||||||
filter_matches(related, query.filter, domain, context[:tenant]),
|
filter_matches(
|
||||||
|
related,
|
||||||
|
query.filter,
|
||||||
|
domain,
|
||||||
|
context[:tenant],
|
||||||
|
context[:actor]
|
||||||
|
),
|
||||||
sorted <- Sort.runtime_sort(filtered, query.sort, domain: domain) do
|
sorted <- Sort.runtime_sort(filtered, query.sort, domain: domain) do
|
||||||
field = field || Enum.at(Ash.Resource.Info.primary_key(query.resource), 0)
|
field = field || Enum.at(Ash.Resource.Info.primary_key(query.resource), 0)
|
||||||
|
|
||||||
|
@ -1015,14 +1035,23 @@ defmodule Ash.DataLayer.Ets do
|
||||||
filter,
|
filter,
|
||||||
domain,
|
domain,
|
||||||
_tenant,
|
_tenant,
|
||||||
|
actor,
|
||||||
parent \\ nil,
|
parent \\ nil,
|
||||||
conflicting_upsert_values \\ nil
|
conflicting_upsert_values \\ nil
|
||||||
)
|
)
|
||||||
|
|
||||||
defp filter_matches([], _, _domain, _tenant, _parent, _conflicting_upsert_values),
|
defp filter_matches([], _, _domain, _tenant, _actor, _parent, _conflicting_upsert_values),
|
||||||
do: {:ok, []}
|
do: {:ok, []}
|
||||||
|
|
||||||
defp filter_matches(records, nil, _domain, _tenant, _parent, _conflicting_upsert_values),
|
defp filter_matches(
|
||||||
|
records,
|
||||||
|
nil,
|
||||||
|
_domain,
|
||||||
|
_tenant,
|
||||||
|
_actor,
|
||||||
|
_parent,
|
||||||
|
_conflicting_upsert_values
|
||||||
|
),
|
||||||
do: {:ok, records}
|
do: {:ok, records}
|
||||||
|
|
||||||
defp filter_matches(
|
defp filter_matches(
|
||||||
|
@ -1030,12 +1059,14 @@ defmodule Ash.DataLayer.Ets do
|
||||||
filter,
|
filter,
|
||||||
domain,
|
domain,
|
||||||
tenant,
|
tenant,
|
||||||
|
actor,
|
||||||
parent,
|
parent,
|
||||||
conflicting_upsert_values
|
conflicting_upsert_values
|
||||||
) do
|
) do
|
||||||
Ash.Filter.Runtime.filter_matches(domain, records, filter,
|
Ash.Filter.Runtime.filter_matches(domain, records, filter,
|
||||||
parent: parent,
|
parent: parent,
|
||||||
tenant: tenant,
|
tenant: tenant,
|
||||||
|
actor: actor,
|
||||||
conflicting_upsert_values: conflicting_upsert_values
|
conflicting_upsert_values: conflicting_upsert_values
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -1137,8 +1168,9 @@ defmodule Ash.DataLayer.Ets do
|
||||||
[result],
|
[result],
|
||||||
filter,
|
filter,
|
||||||
domain,
|
domain,
|
||||||
|
context.private[:tenant],
|
||||||
|
context.private[:actor],
|
||||||
nil,
|
nil,
|
||||||
context[:tenant],
|
|
||||||
conflicting_upsert_values
|
conflicting_upsert_values
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -1383,10 +1415,17 @@ defmodule Ash.DataLayer.Ets do
|
||||||
@doc false
|
@doc false
|
||||||
@impl true
|
@impl true
|
||||||
def destroy(resource, %{data: record, filter: filter} = changeset) do
|
def destroy(resource, %{data: record, filter: filter} = changeset) do
|
||||||
do_destroy(resource, record, changeset.tenant, filter, changeset.domain)
|
do_destroy(
|
||||||
|
resource,
|
||||||
|
record,
|
||||||
|
changeset.tenant,
|
||||||
|
filter,
|
||||||
|
changeset.domain,
|
||||||
|
changeset.context[:private][:actor]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_destroy(resource, record, tenant, filter, domain) do
|
defp do_destroy(resource, record, tenant, filter, domain, actor) do
|
||||||
with {:ok, table} <- wrap_or_create_table(resource, tenant) do
|
with {:ok, table} <- wrap_or_create_table(resource, tenant) do
|
||||||
pkey = Map.take(record, Ash.Resource.Info.primary_key(resource))
|
pkey = Map.take(record, Ash.Resource.Info.primary_key(resource))
|
||||||
|
|
||||||
|
@ -1394,7 +1433,7 @@ defmodule Ash.DataLayer.Ets do
|
||||||
case ETS.Set.get(table, pkey) do
|
case ETS.Set.get(table, pkey) do
|
||||||
{:ok, {_key, record}} when is_map(record) ->
|
{:ok, {_key, record}} when is_map(record) ->
|
||||||
with {:ok, record} <- cast_record(record, resource),
|
with {:ok, record} <- cast_record(record, resource),
|
||||||
{:ok, [_]} <- filter_matches([record], filter, domain, tenant) do
|
{:ok, [_]} <- filter_matches([record], filter, domain, tenant, actor) do
|
||||||
with {:ok, _} <- ETS.Set.delete(table, pkey) do
|
with {:ok, _} <- ETS.Set.delete(table, pkey) do
|
||||||
:ok
|
:ok
|
||||||
end
|
end
|
||||||
|
@ -1489,7 +1528,8 @@ defmodule Ash.DataLayer.Ets do
|
||||||
{pkey, changeset.attributes, changeset.atomics, changeset.filter},
|
{pkey, changeset.attributes, changeset.atomics, changeset.filter},
|
||||||
changeset.domain,
|
changeset.domain,
|
||||||
changeset.tenant,
|
changeset.tenant,
|
||||||
resource
|
resource,
|
||||||
|
changeset.context[:private][:actor]
|
||||||
),
|
),
|
||||||
{:ok, record} <- cast_record(record, resource) do
|
{:ok, record} <- cast_record(record, resource) do
|
||||||
new_pkey = pkey_map(resource, record)
|
new_pkey = pkey_map(resource, record)
|
||||||
|
@ -1534,7 +1574,14 @@ defmodule Ash.DataLayer.Ets do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_update(table, {pkey, record, atomics, changeset_filter}, domain, tenant, resource) do
|
defp do_update(
|
||||||
|
table,
|
||||||
|
{pkey, record, atomics, changeset_filter},
|
||||||
|
domain,
|
||||||
|
tenant,
|
||||||
|
resource,
|
||||||
|
actor
|
||||||
|
) do
|
||||||
attributes = resource |> Ash.Resource.Info.attributes()
|
attributes = resource |> Ash.Resource.Info.attributes()
|
||||||
|
|
||||||
case dump_to_native(record, attributes) do
|
case dump_to_native(record, attributes) do
|
||||||
|
@ -1543,7 +1590,7 @@ defmodule Ash.DataLayer.Ets do
|
||||||
{:ok, {_key, record}} when is_map(record) ->
|
{:ok, {_key, record}} when is_map(record) ->
|
||||||
with {:ok, casted_record} <- cast_record(record, resource),
|
with {:ok, casted_record} <- cast_record(record, resource),
|
||||||
{:ok, [casted_record]} <-
|
{:ok, [casted_record]} <-
|
||||||
filter_matches([casted_record], changeset_filter, domain, tenant) do
|
filter_matches([casted_record], changeset_filter, domain, tenant, actor) do
|
||||||
case atomics do
|
case atomics do
|
||||||
empty when empty in [nil, []] ->
|
empty when empty in [nil, []] ->
|
||||||
data = Map.merge(record, casted)
|
data = Map.merge(record, casted)
|
||||||
|
|
|
@ -70,6 +70,7 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
:limit,
|
:limit,
|
||||||
:tenant,
|
:tenant,
|
||||||
:sort,
|
:sort,
|
||||||
|
context: %{},
|
||||||
relationships: %{},
|
relationships: %{},
|
||||||
offset: 0,
|
offset: 0,
|
||||||
aggregates: [],
|
aggregates: [],
|
||||||
|
@ -203,7 +204,12 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
},
|
},
|
||||||
{:ok, acc} ->
|
{:ok, acc} ->
|
||||||
results
|
results
|
||||||
|> filter_matches(Map.get(query || %{}, :filter), domain, query.tenant)
|
|> filter_matches(
|
||||||
|
Map.get(query || %{}, :filter),
|
||||||
|
domain,
|
||||||
|
query.tenant,
|
||||||
|
query.context[:private][:actor]
|
||||||
|
)
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, matches} ->
|
{:ok, matches} ->
|
||||||
field = field || Enum.at(Ash.Resource.Info.primary_key(resource), 0)
|
field = field || Enum.at(Ash.Resource.Info.primary_key(resource), 0)
|
||||||
|
@ -243,6 +249,12 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
{:ok, %{query | tenant: tenant}}
|
{:ok, %{query | tenant: tenant}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@doc false
|
||||||
|
@impl true
|
||||||
|
def set_context(_resource, query, context) do
|
||||||
|
{:ok, %{query | context: context}}
|
||||||
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
@impl true
|
@impl true
|
||||||
def run_query(
|
def run_query(
|
||||||
|
@ -255,7 +267,8 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
limit: limit,
|
limit: limit,
|
||||||
sort: sort,
|
sort: sort,
|
||||||
aggregates: aggregates,
|
aggregates: aggregates,
|
||||||
tenant: tenant
|
tenant: tenant,
|
||||||
|
context: context
|
||||||
},
|
},
|
||||||
_resource
|
_resource
|
||||||
) do
|
) do
|
||||||
|
@ -265,7 +278,8 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
end),
|
end),
|
||||||
{:ok, records} <-
|
{:ok, records} <-
|
||||||
records |> Enum.map(&elem(&1, 2)) |> Ash.DataLayer.Ets.cast_records(resource),
|
records |> Enum.map(&elem(&1, 2)) |> Ash.DataLayer.Ets.cast_records(resource),
|
||||||
{:ok, filtered} <- filter_matches(records, filter, domain, tenant),
|
{:ok, filtered} <-
|
||||||
|
filter_matches(records, filter, domain, tenant, context[:private][:actor]),
|
||||||
offset_records <-
|
offset_records <-
|
||||||
filtered |> Sort.runtime_sort(sort, domain: domain) |> Enum.drop(offset || 0),
|
filtered |> Sort.runtime_sort(sort, domain: domain) |> Enum.drop(offset || 0),
|
||||||
limited_records <- do_limit(offset_records, limit),
|
limited_records <- do_limit(offset_records, limit),
|
||||||
|
@ -296,10 +310,10 @@ defmodule Ash.DataLayer.Mnesia do
|
||||||
defp do_limit(records, nil), do: records
|
defp do_limit(records, nil), do: records
|
||||||
defp do_limit(records, limit), do: Enum.take(records, limit)
|
defp do_limit(records, limit), do: Enum.take(records, limit)
|
||||||
|
|
||||||
defp filter_matches(records, nil, _domain, _tenant), do: {:ok, records}
|
defp filter_matches(records, nil, _domain, _tenant, _), do: {:ok, records}
|
||||||
|
|
||||||
defp filter_matches(records, filter, domain, tenant) do
|
defp filter_matches(records, filter, domain, tenant, actor) do
|
||||||
Ash.Filter.Runtime.filter_matches(domain, records, filter, tenant: tenant)
|
Ash.Filter.Runtime.filter_matches(domain, records, filter, tenant: tenant, actor: actor)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
|
|
|
@ -29,7 +29,18 @@ defmodule Ash.DataLayer.Simple do
|
||||||
|
|
||||||
defmodule Query do
|
defmodule Query do
|
||||||
@moduledoc false
|
@moduledoc false
|
||||||
defstruct [:data, :resource, :filter, :domain, :limit, :offset, sort: [], data_set?: false]
|
defstruct [
|
||||||
|
:data,
|
||||||
|
:resource,
|
||||||
|
:filter,
|
||||||
|
:domain,
|
||||||
|
:limit,
|
||||||
|
:offset,
|
||||||
|
:tenant,
|
||||||
|
sort: [],
|
||||||
|
data_set?: false,
|
||||||
|
context: %{}
|
||||||
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -60,11 +71,20 @@ defmodule Ash.DataLayer.Simple do
|
||||||
end
|
end
|
||||||
|
|
||||||
def run_query(
|
def run_query(
|
||||||
%{data: data, sort: sort, domain: domain, filter: filter, limit: limit, offset: offset},
|
%{
|
||||||
|
data: data,
|
||||||
|
sort: sort,
|
||||||
|
domain: domain,
|
||||||
|
filter: filter,
|
||||||
|
limit: limit,
|
||||||
|
offset: offset,
|
||||||
|
tenant: tenant,
|
||||||
|
context: context
|
||||||
|
},
|
||||||
_resource
|
_resource
|
||||||
) do
|
) do
|
||||||
data
|
data
|
||||||
|> do_filter_matches(filter, domain)
|
|> do_filter_matches(filter, domain, tenant, context)
|
||||||
|> case do
|
|> case do
|
||||||
{:ok, results} ->
|
{:ok, results} ->
|
||||||
{:ok,
|
{:ok,
|
||||||
|
@ -90,8 +110,11 @@ defmodule Ash.DataLayer.Simple do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_filter_matches(data, filter, domain) do
|
defp do_filter_matches(data, filter, domain, tenant, context) do
|
||||||
Ash.Filter.Runtime.filter_matches(domain, data, filter)
|
Ash.Filter.Runtime.filter_matches(domain, data, filter,
|
||||||
|
actor: context[:private][:actor],
|
||||||
|
tenant: tenant
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
|
@ -105,7 +128,7 @@ defmodule Ash.DataLayer.Simple do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def set_tenant(_, query, _), do: {:ok, query}
|
def set_tenant(_, query, tenant), do: {:ok, %{query | tenant: tenant}}
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
def filter(query, filter, _resource) do
|
def filter(query, filter, _resource) do
|
||||||
|
@ -122,7 +145,7 @@ defmodule Ash.DataLayer.Simple do
|
||||||
with {:ok, data_layer_context} <- Map.fetch(context, :data_layer),
|
with {:ok, data_layer_context} <- Map.fetch(context, :data_layer),
|
||||||
{:ok, data} <- Map.fetch(data_layer_context, :data),
|
{:ok, data} <- Map.fetch(data_layer_context, :data),
|
||||||
{:ok, resource_data} <- Map.fetch(data, query.resource) do
|
{:ok, resource_data} <- Map.fetch(data, query.resource) do
|
||||||
{:ok, %{query | data_set?: true, data: resource_data || []}}
|
{:ok, %{query | data_set?: true, data: resource_data || [], context: context}}
|
||||||
else
|
else
|
||||||
_ ->
|
_ ->
|
||||||
{:ok, query}
|
{:ok, query}
|
||||||
|
|
|
@ -111,7 +111,9 @@ defmodule Ash.Expr do
|
||||||
opts[:parent],
|
opts[:parent],
|
||||||
opts[:resource],
|
opts[:resource],
|
||||||
opts[:domain],
|
opts[:domain],
|
||||||
opts[:unknown_on_unknown_refs?]
|
opts[:unknown_on_unknown_refs?],
|
||||||
|
opts[:actor],
|
||||||
|
opts[:tenant]
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,12 @@ defmodule Ash.Filter.Runtime do
|
||||||
|> load_all(refs_to_load)
|
|> load_all(refs_to_load)
|
||||||
|> Ash.Query.set_context(%{private: %{internal?: true}})
|
|> Ash.Query.set_context(%{private: %{internal?: true}})
|
||||||
|
|
||||||
Ash.load!(records, load, authorize?: false, domain: domain, tenant: opts[:tenant])
|
Ash.load!(records, load,
|
||||||
|
authorize?: false,
|
||||||
|
domain: domain,
|
||||||
|
tenant: opts[:tenant],
|
||||||
|
actor: opts[:actor]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
Enum.reduce_while(records, {:ok, []}, fn record, {:ok, records} ->
|
Enum.reduce_while(records, {:ok, []}, fn record, {:ok, records} ->
|
||||||
|
@ -166,7 +171,9 @@ defmodule Ash.Filter.Runtime do
|
||||||
parent \\ nil,
|
parent \\ nil,
|
||||||
resource \\ nil,
|
resource \\ nil,
|
||||||
domain \\ nil,
|
domain \\ nil,
|
||||||
unknown_on_unknown_refs? \\ false
|
unknown_on_unknown_refs? \\ false,
|
||||||
|
actor \\ nil,
|
||||||
|
tenant \\ nil
|
||||||
) do
|
) do
|
||||||
if domain && record do
|
if domain && record do
|
||||||
refs_to_load =
|
refs_to_load =
|
||||||
|
@ -187,7 +194,12 @@ defmodule Ash.Filter.Runtime do
|
||||||
|> load_all(refs)
|
|> load_all(refs)
|
||||||
|> Ash.Query.set_context(%{private: %{internal?: true}})
|
|> Ash.Query.set_context(%{private: %{internal?: true}})
|
||||||
|
|
||||||
Ash.load!(record, load, domain: domain, authorize?: false)
|
Ash.load!(record, load,
|
||||||
|
domain: domain,
|
||||||
|
authorize?: false,
|
||||||
|
tenant: tenant,
|
||||||
|
actor: actor
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
do_match(record, expression, parent, resource, unknown_on_unknown_refs?)
|
do_match(record, expression, parent, resource, unknown_on_unknown_refs?)
|
||||||
|
@ -451,7 +463,7 @@ defmodule Ash.Filter.Runtime do
|
||||||
if unknown_on_unknown_refs? do
|
if unknown_on_unknown_refs? do
|
||||||
:unknown
|
:unknown
|
||||||
else
|
else
|
||||||
nil
|
{:ok, nil}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,7 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
|
|
||||||
defp try_eval(expression, %{
|
defp try_eval(expression, %{
|
||||||
resource: resource,
|
resource: resource,
|
||||||
action_input: %Ash.ActionInput{} = action_input,
|
action_input: %Ash.ActionInput{tenant: tenant} = action_input,
|
||||||
actor: actor
|
actor: actor
|
||||||
}) do
|
}) do
|
||||||
expression =
|
expression =
|
||||||
|
@ -140,22 +140,12 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
public?: false
|
public?: false
|
||||||
}) do
|
}) do
|
||||||
{:ok, hydrated} ->
|
{:ok, hydrated} ->
|
||||||
Ash.Expr.eval_hydrated(hydrated, resource: resource, unknown_on_unknown_refs?: true)
|
Ash.Expr.eval_hydrated(hydrated,
|
||||||
|
|
||||||
{:error, error} ->
|
|
||||||
{:error, error}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
defp try_eval(expression, %{resource: resource, query: %Ash.Query{} = query}) do
|
|
||||||
case Ash.Filter.hydrate_refs(expression, %{
|
|
||||||
resource: resource,
|
resource: resource,
|
||||||
aggregates: query.aggregates,
|
unknown_on_unknown_refs?: true,
|
||||||
calculations: query.calculations,
|
actor: actor,
|
||||||
public?: false
|
tenant: tenant
|
||||||
}) do
|
)
|
||||||
{:ok, hydrated} ->
|
|
||||||
Ash.Expr.eval_hydrated(hydrated, resource: resource, unknown_on_unknown_refs?: true)
|
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
@ -164,7 +154,31 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
|
|
||||||
defp try_eval(expression, %{
|
defp try_eval(expression, %{
|
||||||
resource: resource,
|
resource: resource,
|
||||||
changeset: %Ash.Changeset{action_type: :create} = changeset,
|
query: %Ash.Query{tenant: tenant} = query,
|
||||||
|
actor: actor
|
||||||
|
}) do
|
||||||
|
case Ash.Filter.hydrate_refs(expression, %{
|
||||||
|
resource: resource,
|
||||||
|
aggregates: query.aggregates,
|
||||||
|
calculations: query.calculations,
|
||||||
|
public?: false
|
||||||
|
}) do
|
||||||
|
{:ok, hydrated} ->
|
||||||
|
Ash.Expr.eval_hydrated(hydrated,
|
||||||
|
resource: resource,
|
||||||
|
unknown_on_unknown_refs?: true,
|
||||||
|
actor: actor,
|
||||||
|
tenant: tenant
|
||||||
|
)
|
||||||
|
|
||||||
|
{:error, error} ->
|
||||||
|
{:error, error}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp try_eval(expression, %{
|
||||||
|
resource: resource,
|
||||||
|
changeset: %Ash.Changeset{action_type: :create, tenant: tenant} = changeset,
|
||||||
actor: actor
|
actor: actor
|
||||||
}) do
|
}) do
|
||||||
expression =
|
expression =
|
||||||
|
@ -184,7 +198,12 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
public?: false
|
public?: false
|
||||||
}) do
|
}) do
|
||||||
{:ok, hydrated} ->
|
{:ok, hydrated} ->
|
||||||
Ash.Expr.eval_hydrated(hydrated, resource: resource, unknown_on_unknown_refs?: true)
|
Ash.Expr.eval_hydrated(hydrated,
|
||||||
|
resource: resource,
|
||||||
|
unknown_on_unknown_refs?: true,
|
||||||
|
actor: actor,
|
||||||
|
tenant: tenant
|
||||||
|
)
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
@ -193,7 +212,8 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
|
|
||||||
defp try_eval(expression, %{
|
defp try_eval(expression, %{
|
||||||
resource: resource,
|
resource: resource,
|
||||||
changeset: %Ash.Changeset{data: data} = changeset
|
changeset: %Ash.Changeset{data: data, tenant: tenant} = changeset,
|
||||||
|
actor: actor
|
||||||
}) do
|
}) do
|
||||||
case Ash.Filter.hydrate_refs(expression, %{
|
case Ash.Filter.hydrate_refs(expression, %{
|
||||||
resource: resource,
|
resource: resource,
|
||||||
|
@ -204,7 +224,9 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
{:ok, hydrated} ->
|
{:ok, hydrated} ->
|
||||||
opts = [
|
opts = [
|
||||||
resource: resource,
|
resource: resource,
|
||||||
unknown_on_unknown_refs?: true
|
unknown_on_unknown_refs?: true,
|
||||||
|
actor: actor,
|
||||||
|
tenant: tenant
|
||||||
]
|
]
|
||||||
|
|
||||||
# We don't want to authorize on stale data in real life
|
# We don't want to authorize on stale data in real life
|
||||||
|
@ -231,7 +253,7 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp try_eval(expression, %{resource: resource}) do
|
defp try_eval(expression, %{resource: resource, actor: actor}) do
|
||||||
case Ash.Filter.hydrate_refs(expression, %{
|
case Ash.Filter.hydrate_refs(expression, %{
|
||||||
resource: resource,
|
resource: resource,
|
||||||
aggregates: %{},
|
aggregates: %{},
|
||||||
|
@ -239,7 +261,11 @@ defmodule Ash.Policy.FilterCheck do
|
||||||
public?: false
|
public?: false
|
||||||
}) do
|
}) do
|
||||||
{:ok, hydrated} ->
|
{:ok, hydrated} ->
|
||||||
Ash.Expr.eval_hydrated(hydrated, resource: resource, unknown_on_unknown_refs?: true)
|
Ash.Expr.eval_hydrated(hydrated,
|
||||||
|
resource: resource,
|
||||||
|
unknown_on_unknown_refs?: true,
|
||||||
|
actor: actor
|
||||||
|
)
|
||||||
|
|
||||||
{:error, error} ->
|
{:error, error} ->
|
||||||
{:error, error}
|
{:error, error}
|
||||||
|
|
|
@ -2913,7 +2913,11 @@ defmodule Ash.Query do
|
||||||
"Could not determine domain for #{inspect(query)}, please provide the `:domain` option."
|
"Could not determine domain for #{inspect(query)}, please provide the `:domain` option."
|
||||||
|
|
||||||
with {:ok, records} <-
|
with {:ok, records} <-
|
||||||
Ash.Filter.Runtime.filter_matches(domain, records, query.filter, parent: opts[:parent]),
|
Ash.Filter.Runtime.filter_matches(domain, records, query.filter,
|
||||||
|
parent: opts[:parent],
|
||||||
|
actor: opts[:actor] || query.context[:private][:actor],
|
||||||
|
tenant: opts[:tenant] || query.tenant
|
||||||
|
),
|
||||||
records <- Sort.runtime_sort(records, query.distinct_sort || query.sort, domain: domain),
|
records <- Sort.runtime_sort(records, query.distinct_sort || query.sort, domain: domain),
|
||||||
records <- Sort.runtime_distinct(records, query.distinct, domain: domain),
|
records <- Sort.runtime_distinct(records, query.distinct, domain: domain),
|
||||||
records <- Sort.runtime_sort(records, query.sort, domain: domain),
|
records <- Sort.runtime_sort(records, query.sort, domain: domain),
|
||||||
|
|
|
@ -45,6 +45,7 @@ defmodule Ash.Resource.Calculation.Expression do
|
||||||
case Ash.Expr.eval_hydrated(expression,
|
case Ash.Expr.eval_hydrated(expression,
|
||||||
record: record,
|
record: record,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
|
actor: context.actor,
|
||||||
unknown_on_unknown_refs?: true
|
unknown_on_unknown_refs?: true
|
||||||
) do
|
) do
|
||||||
{:ok, value} ->
|
{:ok, value} ->
|
||||||
|
|
|
@ -264,12 +264,11 @@ defmodule Ash.Type.Struct do
|
||||||
else
|
else
|
||||||
keys = Map.keys(value)
|
keys = Map.keys(value)
|
||||||
|
|
||||||
cond do
|
if Enum.all?(keys, &is_atom/1) do
|
||||||
Enum.all?(keys, &is_atom/1) ->
|
|
||||||
{:ok, struct(struct, value)}
|
{:ok, struct(struct, value)}
|
||||||
|
else
|
||||||
Enum.all?(keys, &is_binary/1) ->
|
{:ok,
|
||||||
{:ok, Map.delete(struct.__struct__, :__struct__)}
|
Map.delete(struct.__struct__, :__struct__)
|
||||||
|> Enum.reduce({:ok, struct(struct)}, fn {key, _value}, {:ok, acc} ->
|
|> Enum.reduce({:ok, struct(struct)}, fn {key, _value}, {:ok, acc} ->
|
||||||
case Map.fetch(value, to_string(key)) do
|
case Map.fetch(value, to_string(key)) do
|
||||||
{:ok, val} ->
|
{:ok, val} ->
|
||||||
|
@ -278,7 +277,7 @@ defmodule Ash.Type.Struct do
|
||||||
:error ->
|
:error ->
|
||||||
{:ok, acc}
|
{:ok, acc}
|
||||||
end
|
end
|
||||||
end)
|
end)}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue