mirror of
https://github.com/ash-project/ash.git
synced 2024-09-19 13:03:02 +12:00
improvement: make long-awaited DSL name changes
This commit is contained in:
parent
44adc9a1b8
commit
6c79519b6c
53 changed files with 456 additions and 432 deletions
|
@ -18,6 +18,7 @@ locals_without_parens = [
|
|||
attribute: 1,
|
||||
attribute: 2,
|
||||
attribute: 3,
|
||||
attribute_type: 1,
|
||||
attribute_writable?: 1,
|
||||
authorize: 1,
|
||||
authorize_if: 1,
|
||||
|
@ -55,11 +56,11 @@ locals_without_parens = [
|
|||
defaults: 1,
|
||||
define: 1,
|
||||
define: 2,
|
||||
define_field?: 1,
|
||||
define_attribute?: 1,
|
||||
define_for: 1,
|
||||
description: 1,
|
||||
destination_field: 1,
|
||||
destination_field_on_join_table: 1,
|
||||
destination_attribute: 1,
|
||||
destination_attribute_on_join_resource: 1,
|
||||
destroy: 1,
|
||||
destroy: 2,
|
||||
destroy: 3,
|
||||
|
@ -70,9 +71,7 @@ locals_without_parens = [
|
|||
entry: 2,
|
||||
error_handler: 1,
|
||||
event: 1,
|
||||
expensive?: 1,
|
||||
field: 1,
|
||||
field_type: 1,
|
||||
filter: 1,
|
||||
filterable?: 1,
|
||||
first: 3,
|
||||
|
@ -113,7 +112,7 @@ locals_without_parens = [
|
|||
modify_query: 1,
|
||||
module: 1,
|
||||
name: 1,
|
||||
no_fields?: 1,
|
||||
no_attributes?: 1,
|
||||
not_found_message: 1,
|
||||
on: 1,
|
||||
only_when_valid?: 1,
|
||||
|
@ -153,8 +152,8 @@ locals_without_parens = [
|
|||
soft?: 1,
|
||||
sort: 1,
|
||||
source: 1,
|
||||
source_field: 1,
|
||||
source_field_on_join_table: 1,
|
||||
source_attribute: 1,
|
||||
source_attribute_on_join_resource: 1,
|
||||
strategy: 1,
|
||||
sum: 3,
|
||||
sum: 4,
|
||||
|
@ -180,7 +179,7 @@ locals_without_parens = [
|
|||
uuid_primary_key: 2,
|
||||
validate: 1,
|
||||
validate: 2,
|
||||
validate_destination_field?: 1,
|
||||
validate_destination_attribute?: 1,
|
||||
violation_message: 1,
|
||||
wait_for: 1,
|
||||
warn_on_empty?: 1,
|
||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -456,7 +456,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
* use new `no_depend_modules` everywhere
|
||||
|
||||
* add `no_fields?` relationships
|
||||
* add `no_attributes?` relationships
|
||||
|
||||
* add manual read actions
|
||||
|
||||
|
@ -2082,7 +2082,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
### Improvements:
|
||||
|
||||
* add `validate_destination_field?`
|
||||
* add `validate_destination_attribute?`
|
||||
|
||||
* add builtin `select` change
|
||||
|
||||
|
@ -2813,7 +2813,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
### Bug Fixes:
|
||||
|
||||
* set `source_field` when replacing `belongs_to` relationship
|
||||
* set `source_attribute` when replacing `belongs_to` relationship
|
||||
|
||||
* don't consider `false` as absent value
|
||||
|
||||
|
@ -2913,7 +2913,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
### Improvements:
|
||||
|
||||
* derive has_one destination_field
|
||||
* derive has_one destination_attribute
|
||||
|
||||
* finalize code API logic
|
||||
|
||||
|
@ -3077,7 +3077,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
* many compile time fixes via code splitting
|
||||
|
||||
* Guess destination_field for has many relationships (#187)
|
||||
* Guess destination_attribute for has many relationships (#187)
|
||||
|
||||
* Implement string length validation (#183)
|
||||
|
||||
|
@ -3090,7 +3090,7 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
* many compile time fixes via code splitting
|
||||
|
||||
* Guess destination_field for has many relationships (#187)
|
||||
* Guess destination_attribute for has many relationships (#187)
|
||||
|
||||
* Implement string length validation (#183)
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ defmodule Ash.Actions.Load do
|
|||
else
|
||||
related_query
|
||||
end
|
||||
|> Ash.Query.ensure_selected(relationship.destination_field)
|
||||
|> Ash.Query.ensure_selected(relationship.destination_attribute)
|
||||
|
||||
related_query =
|
||||
if relationship.cardinality == :one do
|
||||
|
@ -75,10 +75,10 @@ defmodule Ash.Actions.Load do
|
|||
)
|
||||
|
||||
query =
|
||||
if Map.get(relationship, :no_fields?) do
|
||||
if Map.get(relationship, :no_attributes?) do
|
||||
query
|
||||
else
|
||||
Ash.Query.ensure_selected(query, relationship.source_field)
|
||||
Ash.Query.ensure_selected(query, relationship.source_attribute)
|
||||
end
|
||||
|
||||
{
|
||||
|
@ -139,7 +139,7 @@ defmodule Ash.Actions.Load do
|
|||
data
|
||||
end
|
||||
|
||||
defp attach_to_many_loads(value, %{name: name, no_fields?: true}, data, lead_path) do
|
||||
defp attach_to_many_loads(value, %{name: name, no_attributes?: true}, data, lead_path) do
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
Map.put(record, name, List.wrap(value))
|
||||
end)
|
||||
|
@ -154,16 +154,16 @@ defmodule Ash.Actions.Load do
|
|||
end
|
||||
|
||||
defp attach_to_many_loads(value, last_relationship, data, lead_path) do
|
||||
values = Enum.group_by(value, &Map.get(&1, last_relationship.destination_field))
|
||||
values = Enum.group_by(value, &Map.get(&1, last_relationship.destination_attribute))
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
source_key = Map.get(record, last_relationship.source_field)
|
||||
source_key = Map.get(record, last_relationship.source_attribute)
|
||||
related_records = Map.get(values, source_key, [])
|
||||
Map.put(record, last_relationship.name, related_records)
|
||||
end)
|
||||
end
|
||||
|
||||
defp attach_to_one_loads(value, %{name: name, no_fields?: true}, data, lead_path) do
|
||||
defp attach_to_one_loads(value, %{name: name, no_attributes?: true}, data, lead_path) do
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
Map.put(record, name, value |> List.wrap() |> Enum.at(0))
|
||||
end)
|
||||
|
@ -182,11 +182,11 @@ defmodule Ash.Actions.Load do
|
|||
value
|
||||
|> Enum.reverse()
|
||||
|> Enum.into(%{}, fn item ->
|
||||
{Map.get(item, last_relationship.destination_field), item}
|
||||
{Map.get(item, last_relationship.destination_attribute), item}
|
||||
end)
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
source_key = Map.get(record, last_relationship.source_field)
|
||||
source_key = Map.get(record, last_relationship.source_attribute)
|
||||
related_record = Map.get(values, source_key)
|
||||
Map.put(record, last_relationship.name, related_record)
|
||||
end)
|
||||
|
@ -201,20 +201,20 @@ defmodule Ash.Actions.Load do
|
|||
|> Map.get(:data, [])
|
||||
|
||||
map_or_update(data, lead_path, fn record ->
|
||||
source_value = Map.get(record, last_relationship.source_field)
|
||||
source_value = Map.get(record, last_relationship.source_attribute)
|
||||
|
||||
join_values =
|
||||
join_data
|
||||
|> Enum.filter(fn join_row ->
|
||||
Map.get(join_row, last_relationship.source_field_on_join_table) ==
|
||||
Map.get(join_row, last_relationship.source_attribute_on_join_resource) ==
|
||||
source_value
|
||||
end)
|
||||
|> Enum.map(&Map.get(&1, last_relationship.destination_field_on_join_table))
|
||||
|> Enum.map(&Map.get(&1, last_relationship.destination_attribute_on_join_resource))
|
||||
|
||||
related_records =
|
||||
value
|
||||
|> Enum.filter(fn value ->
|
||||
destination_value = Map.get(value, last_relationship.destination_field)
|
||||
destination_value = Map.get(value, last_relationship.destination_attribute)
|
||||
|
||||
destination_value in join_values
|
||||
end)
|
||||
|
@ -742,10 +742,10 @@ defmodule Ash.Actions.Load do
|
|||
end
|
||||
|> List.wrap()
|
||||
|> Enum.map(fn related ->
|
||||
Map.get(related, relationship.destination_field)
|
||||
Map.get(related, relationship.destination_attribute)
|
||||
end)
|
||||
|
||||
filter = [{relationship.destination_field_on_join_table, [{:in, ids}]}]
|
||||
filter = [{relationship.destination_attribute_on_join_resource, [{:in, ids}]}]
|
||||
|
||||
Ash.Query.filter(query, ^filter)
|
||||
end
|
||||
|
@ -841,10 +841,10 @@ defmodule Ash.Actions.Load do
|
|||
lateral_join_source: {
|
||||
source_data,
|
||||
[
|
||||
{source_query, relationship.source_field,
|
||||
relationship.source_field_on_join_table, relationship},
|
||||
{relationship.through, relationship.destination_field_on_join_table,
|
||||
relationship.destination_field, join_relationship}
|
||||
{source_query, relationship.source_attribute,
|
||||
relationship.source_attribute_on_join_resource, relationship},
|
||||
{relationship.through, relationship.destination_attribute_on_join_resource,
|
||||
relationship.destination_attribute, join_relationship}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -862,8 +862,8 @@ defmodule Ash.Actions.Load do
|
|||
lateral_join_source:
|
||||
{source_data,
|
||||
[
|
||||
{source_query, relationship.source_field, relationship.destination_field,
|
||||
relationship}
|
||||
{source_query, relationship.source_attribute,
|
||||
relationship.destination_attribute, relationship}
|
||||
]}
|
||||
}
|
||||
})
|
||||
|
@ -908,7 +908,7 @@ defmodule Ash.Actions.Load do
|
|||
new_results =
|
||||
results
|
||||
|> Enum.group_by(fn record ->
|
||||
Map.get(record, relationship.destination_field)
|
||||
Map.get(record, relationship.destination_attribute)
|
||||
end)
|
||||
|> Enum.flat_map(fn {_, group} ->
|
||||
offset_records = Enum.drop(group, offset || 0)
|
||||
|
@ -999,7 +999,7 @@ defmodule Ash.Actions.Load do
|
|||
relationship,
|
||||
related_query
|
||||
) do
|
||||
if Map.get(relationship, :no_fields?) do
|
||||
if Map.get(relationship, :no_attributes?) do
|
||||
relationship.destination
|
||||
|> Ash.Query.new(related_query.api)
|
||||
else
|
||||
|
@ -1010,14 +1010,14 @@ defmodule Ash.Actions.Load do
|
|||
end
|
||||
|
||||
defp true_load_query(relationship, query, data, path, request_path) do
|
||||
{source_field, path} =
|
||||
{source_attribute, path} =
|
||||
if relationship.type == :many_to_many do
|
||||
join_relationship = join_relationship(relationship)
|
||||
|
||||
{relationship.destination_field_on_join_table,
|
||||
{relationship.destination_attribute_on_join_resource,
|
||||
join_relationship_path(path, join_relationship) |> Enum.map(& &1.name)}
|
||||
else
|
||||
{relationship.source_field, path |> Enum.reverse() |> Enum.map(& &1.name)}
|
||||
{relationship.source_attribute, path |> Enum.reverse() |> Enum.map(& &1.name)}
|
||||
end
|
||||
|
||||
source_data =
|
||||
|
@ -1042,18 +1042,18 @@ defmodule Ash.Actions.Load do
|
|||
:nothing
|
||||
|
||||
_ ->
|
||||
get_query(query, relationship, source_data, source_field)
|
||||
get_query(query, relationship, source_data, source_attribute)
|
||||
end
|
||||
end
|
||||
|
||||
defp get_query(query, relationship, source_data, source_field) do
|
||||
defp get_query(query, relationship, source_data, source_attribute) do
|
||||
{offset, limit} = offset_and_limit(query)
|
||||
|
||||
cond do
|
||||
lateral_join?(query, relationship, source_data) ->
|
||||
{:ok, Ash.Query.unset(query, :load)}
|
||||
|
||||
Map.get(relationship, :no_fields?) ->
|
||||
Map.get(relationship, :no_attributes?) ->
|
||||
{:ok, query}
|
||||
|
||||
true ->
|
||||
|
@ -1076,7 +1076,7 @@ defmodule Ash.Actions.Load do
|
|||
ids =
|
||||
Enum.flat_map(related_data, fn data ->
|
||||
data
|
||||
|> Map.get(source_field)
|
||||
|> Map.get(source_attribute)
|
||||
|> List.wrap()
|
||||
end)
|
||||
|
||||
|
@ -1091,7 +1091,7 @@ defmodule Ash.Actions.Load do
|
|||
|
||||
new_query =
|
||||
query
|
||||
|> Ash.Query.filter(^[{relationship.destination_field, filter_value}])
|
||||
|> Ash.Query.filter(^[{relationship.destination_attribute, filter_value}])
|
||||
|> Ash.Query.unset(:load)
|
||||
|
||||
{:ok, new_query}
|
||||
|
@ -1177,12 +1177,12 @@ defmodule Ash.Actions.Load do
|
|||
defp reverse_relationship?(rel, destination_rel) do
|
||||
rel.source == destination_rel.destination &&
|
||||
rel.destination == destination_rel.source &&
|
||||
rel.source_field == destination_rel.destination_field &&
|
||||
rel.destination_field == destination_rel.source_field &&
|
||||
Map.fetch(rel, :source_field_on_join_table) ==
|
||||
Map.fetch(destination_rel, :destination_field_on_join_table) &&
|
||||
Map.fetch(rel, :destination_field_on_join_table) ==
|
||||
Map.fetch(destination_rel, :source_field_on_join_table) &&
|
||||
rel.source_attribute == destination_rel.destination_attribute &&
|
||||
rel.destination_attribute == destination_rel.source_attribute &&
|
||||
Map.fetch(rel, :source_attribute_on_join_resource) ==
|
||||
Map.fetch(destination_rel, :destination_attribute_on_join_resource) &&
|
||||
Map.fetch(rel, :destination_attribute_on_join_resource) ==
|
||||
Map.fetch(destination_rel, :source_attribute_on_join_resource) &&
|
||||
is_nil(destination_rel.context) &&
|
||||
is_nil(rel.context)
|
||||
end
|
||||
|
|
|
@ -103,7 +103,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
changeset =
|
||||
if input in [nil, []] && opts[:on_missing] != :ignore do
|
||||
changeset
|
||||
|> maybe_force_change_attribute(relationship, :source_field, nil)
|
||||
|> maybe_force_change_attribute(relationship, :source_attribute, nil)
|
||||
|> Ash.Changeset.after_action(fn _changeset, result ->
|
||||
{:ok, Map.put(result, relationship.name, nil)}
|
||||
end)
|
||||
|
@ -176,8 +176,8 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
})
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:source_field,
|
||||
Map.get(input, relationship.destination_field)
|
||||
:source_attribute,
|
||||
Map.get(input, relationship.destination_attribute)
|
||||
)
|
||||
|
||||
{:cont, {changeset, instructions}}
|
||||
|
@ -237,8 +237,8 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
})
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:source_field,
|
||||
Map.get(found, relationship.destination_field)
|
||||
:source_attribute,
|
||||
Map.get(found, relationship.destination_attribute)
|
||||
)
|
||||
|
||||
{:cont, {changeset, instructions}}
|
||||
|
@ -259,7 +259,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
maybe_force_change_attribute(
|
||||
changeset,
|
||||
relationship,
|
||||
:source_field,
|
||||
:source_attribute,
|
||||
nil
|
||||
)
|
||||
|
||||
|
@ -315,7 +315,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
relationship.api || changeset.api
|
||||
end
|
||||
|
||||
defp maybe_force_change_attribute(changeset, %{no_fields?: true}, _, _), do: changeset
|
||||
defp maybe_force_change_attribute(changeset, %{no_attributes?: true}, _, _), do: changeset
|
||||
|
||||
defp maybe_force_change_attribute(changeset, relationship, key, value) do
|
||||
Ash.Changeset.force_change_attribute(
|
||||
|
@ -349,7 +349,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
|> Enum.reduce({changeset, instructions}, fn required_relationship,
|
||||
{changeset, instructions} ->
|
||||
changeset =
|
||||
case Ash.Changeset.get_attribute(changeset, required_relationship.source_field) do
|
||||
case Ash.Changeset.get_attribute(changeset, required_relationship.source_attribute) do
|
||||
nil ->
|
||||
Ash.Changeset.add_error(
|
||||
changeset,
|
||||
|
@ -462,8 +462,8 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
})
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:source_field,
|
||||
Map.get(created, relationship.destination_field)
|
||||
:source_attribute,
|
||||
Map.get(created, relationship.destination_attribute)
|
||||
)
|
||||
|
||||
{:cont,
|
||||
|
@ -944,13 +944,13 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:source_field_on_join_table,
|
||||
Map.get(record, relationship.source_field)
|
||||
:source_attribute_on_join_resource,
|
||||
Map.get(record, relationship.source_attribute)
|
||||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:destination_field_on_join_table,
|
||||
Map.get(found, relationship.destination_field)
|
||||
:destination_attribute_on_join_resource,
|
||||
Map.get(found, relationship.destination_attribute)
|
||||
)
|
||||
|> Ash.Changeset.set_context(join_relationship.context)
|
||||
|> Ash.Changeset.set_tenant(changeset.tenant)
|
||||
|
@ -1006,8 +1006,8 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:destination_field,
|
||||
Map.get(record, relationship.source_field)
|
||||
:destination_attribute,
|
||||
Map.get(record, relationship.source_attribute)
|
||||
)
|
||||
|> Ash.Changeset.set_context(relationship.context)
|
||||
|> Ash.Changeset.set_tenant(changeset.tenant)
|
||||
|
@ -1066,8 +1066,8 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:destination_field,
|
||||
Map.get(record, relationship.source_field)
|
||||
:destination_attribute,
|
||||
Map.get(record, relationship.source_attribute)
|
||||
)
|
||||
|> Ash.Changeset.set_context(relationship.context)
|
||||
|> Ash.Changeset.set_tenant(changeset.tenant)
|
||||
|
@ -1134,13 +1134,13 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:source_field_on_join_table,
|
||||
Map.get(record, relationship.source_field)
|
||||
:source_attribute_on_join_resource,
|
||||
Map.get(record, relationship.source_attribute)
|
||||
)
|
||||
|> maybe_force_change_attribute(
|
||||
relationship,
|
||||
:destination_field_on_join_table,
|
||||
Map.get(created, relationship.destination_field)
|
||||
:destination_attribute_on_join_resource,
|
||||
Map.get(created, relationship.destination_attribute)
|
||||
)
|
||||
|> Ash.Changeset.set_context(join_relationship.context)
|
||||
|> Ash.Changeset.set_tenant(changeset.tenant)
|
||||
|
@ -1275,7 +1275,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
{match, regular_params}
|
||||
end
|
||||
|
||||
source_value = Map.get(source_record, relationship.source_field)
|
||||
source_value = Map.get(source_record, relationship.source_attribute)
|
||||
|
||||
match
|
||||
|> Ash.Changeset.new()
|
||||
|
@ -1289,15 +1289,17 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
|> api.update(return_notifications?: true)
|
||||
|> case do
|
||||
{:ok, updated, update_notifications} ->
|
||||
destination_value = Map.get(updated, relationship.destination_field)
|
||||
destination_value = Map.get(updated, relationship.destination_attribute)
|
||||
|
||||
join_relationship =
|
||||
Ash.Resource.Info.relationship(relationship.source, relationship.join_relationship)
|
||||
|
||||
relationship.through
|
||||
|> Ash.Query.filter(ref(^relationship.source_field_on_join_table) == ^source_value)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_field_on_join_table) == ^destination_value
|
||||
ref(^relationship.source_attribute_on_join_resource) == ^source_value
|
||||
)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_attribute_on_join_resource) == ^destination_value
|
||||
)
|
||||
|> Ash.Query.set_context(join_relationship.context)
|
||||
|> Ash.Query.limit(1)
|
||||
|
@ -1367,9 +1369,9 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
|
||||
defp matches?(current_value, input, pkey, relationship) do
|
||||
if relationship && relationship.type in [:has_one, :has_many] &&
|
||||
relationship.destination_field in pkey do
|
||||
relationship.destination_attribute in pkey do
|
||||
Enum.all?(pkey, fn field ->
|
||||
if field == relationship.destination_field do
|
||||
if field == relationship.destination_attribute do
|
||||
if is_struct(input) do
|
||||
do_matches?(current_value, input, field)
|
||||
else
|
||||
|
@ -1445,16 +1447,18 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
{:cont, {:ok, [record | current_value], []}}
|
||||
|
||||
{:destroy, action_name, join_action_name} ->
|
||||
source_value = Map.get(source_record, relationship.source_field)
|
||||
destination_value = Map.get(record, relationship.destination_field)
|
||||
source_value = Map.get(source_record, relationship.source_attribute)
|
||||
destination_value = Map.get(record, relationship.destination_attribute)
|
||||
|
||||
join_relationship =
|
||||
Ash.Resource.Info.relationship(relationship.source, relationship.join_relationship)
|
||||
|
||||
relationship.through
|
||||
|> Ash.Query.filter(ref(^relationship.source_field_on_join_table) == ^source_value)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_field_on_join_table) == ^destination_value
|
||||
ref(^relationship.source_attribute_on_join_resource) == ^source_value
|
||||
)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_attribute_on_join_resource) == ^destination_value
|
||||
)
|
||||
|> Ash.Query.limit(1)
|
||||
|> Ash.Query.set_tenant(changeset.tenant)
|
||||
|
@ -1571,15 +1575,17 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
action_name =
|
||||
action_name || Ash.Resource.Info.primary_action(relationship.through, :destroy).name
|
||||
|
||||
source_value = Map.get(source_record, relationship.source_field)
|
||||
destination_value = Map.get(record, relationship.destination_field)
|
||||
source_value = Map.get(source_record, relationship.source_attribute)
|
||||
destination_value = Map.get(record, relationship.destination_attribute)
|
||||
|
||||
join_relationship =
|
||||
Ash.Resource.Info.relationship(relationship.source, relationship.join_relationship)
|
||||
|
||||
relationship.through
|
||||
|> Ash.Query.filter(ref(^relationship.source_field_on_join_table) == ^source_value)
|
||||
|> Ash.Query.filter(ref(^relationship.destination_field_on_join_table) == ^destination_value)
|
||||
|> Ash.Query.filter(ref(^relationship.source_attribute_on_join_resource) == ^source_value)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_attribute_on_join_resource) == ^destination_value
|
||||
)
|
||||
|> Ash.Query.limit(1)
|
||||
|> Ash.Query.set_tenant(tenant)
|
||||
|> Ash.Query.set_context(join_relationship.context)
|
||||
|
@ -1626,7 +1632,7 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
authorize?: opts[:authorize?],
|
||||
actor: actor
|
||||
)
|
||||
|> maybe_force_change_attribute(relationship, :destination_field, nil)
|
||||
|> maybe_force_change_attribute(relationship, :destination_attribute, nil)
|
||||
|> Ash.Changeset.set_context(relationship.context)
|
||||
|> Ash.Changeset.set_tenant(tenant)
|
||||
|> api.update(return_notifications?: true)
|
||||
|
@ -1665,12 +1671,14 @@ defmodule Ash.Actions.ManagedRelationships do
|
|||
action_name =
|
||||
action_name || Ash.Resource.Info.primary_action(relationship.through, :destroy).name
|
||||
|
||||
source_value = Map.get(source_record, relationship.source_field)
|
||||
destination_value = Map.get(record, relationship.destination_field)
|
||||
source_value = Map.get(source_record, relationship.source_attribute)
|
||||
destination_value = Map.get(record, relationship.destination_attribute)
|
||||
|
||||
relationship.through
|
||||
|> Ash.Query.filter(ref(^relationship.source_field_on_join_table) == ^source_value)
|
||||
|> Ash.Query.filter(ref(^relationship.destination_field_on_join_table) == ^destination_value)
|
||||
|> Ash.Query.filter(ref(^relationship.source_attribute_on_join_resource) == ^source_value)
|
||||
|> Ash.Query.filter(
|
||||
ref(^relationship.destination_attribute_on_join_resource) == ^destination_value
|
||||
)
|
||||
|> Ash.Query.limit(1)
|
||||
|> Ash.Query.set_tenant(tenant)
|
||||
|> api.read_one(authorize?: opts[:authorize?], actor: actor)
|
||||
|
|
|
@ -158,13 +158,13 @@ defmodule Ash.Actions.Sort do
|
|||
{field, {:ok, aggregate.type}}
|
||||
|
||||
%Ash.Resource.Aggregate{} = agg ->
|
||||
field_type =
|
||||
attribute_type =
|
||||
if agg.field do
|
||||
related = Ash.Resource.Info.related(resource, agg.relationship_path)
|
||||
Ash.Resource.Info.attribute(related, agg.field).type
|
||||
end
|
||||
|
||||
{agg.name, Ash.Query.Aggregate.kind_to_type(agg.kind, field_type)}
|
||||
{agg.name, Ash.Query.Aggregate.kind_to_type(agg.kind, attribute_type)}
|
||||
end
|
||||
|
||||
case type do
|
||||
|
|
|
@ -1048,14 +1048,14 @@ defmodule Ash.Changeset do
|
|||
defp validate(changeset, validation) do
|
||||
if validation.before_action? do
|
||||
before_action(changeset, fn changeset ->
|
||||
if validation.expensive? and not changeset.valid? do
|
||||
if validation.only_when_valid? and not changeset.valid? do
|
||||
changeset
|
||||
else
|
||||
do_validation(changeset, validation)
|
||||
end
|
||||
end)
|
||||
else
|
||||
if validation.expensive? and not changeset.valid? do
|
||||
if validation.only_when_valid? and not changeset.valid? do
|
||||
changeset
|
||||
else
|
||||
do_validation(changeset, validation)
|
||||
|
@ -1243,7 +1243,7 @@ defmodule Ash.Changeset do
|
|||
resource
|
||||
|> Ash.Resource.Info.relationships()
|
||||
|> Enum.filter(&(&1.type == :belongs_to))
|
||||
|> Enum.map(& &1.source_field)
|
||||
|> Enum.map(& &1.source_attribute)
|
||||
|
||||
action =
|
||||
case action do
|
||||
|
@ -1690,9 +1690,9 @@ defmodule Ash.Changeset do
|
|||
* `:no_match` - ignores the primary key match and follows the on_no_match instructions with these records instead.
|
||||
* `:unrelate` - the related item is not destroyed, but the data is "unrelated", making this behave like `remove_from_relationship/3`. The action should be:
|
||||
* many_to_many - the join resource row is destroyed
|
||||
* has_many - the destination_field (on the related record) is set to `nil`
|
||||
* has_one - the destination_field (on the related record) is set to `nil`
|
||||
* belongs_to - the source_field (on this record) is set to `nil`
|
||||
* has_many - the destination_attribute (on the related record) is set to `nil`
|
||||
* has_one - the destination_attribute (on the related record) is set to `nil`
|
||||
* belongs_to - the source_attribute (on this record) is set to `nil`
|
||||
* `{:unrelate, :action_name}` - the record is unrelated using the provided update action. The action should be:
|
||||
* many_to_many - a destroy action on the join resource
|
||||
* has_many - an update action on the destination resource
|
||||
|
@ -1713,9 +1713,9 @@ defmodule Ash.Changeset do
|
|||
* `:error` - an error is returned indicating that a record would have been updated
|
||||
* `:unrelate` - the related item is not destroyed, but the data is "unrelated", making this behave like `remove_from_relationship/3`. The action should be:
|
||||
* many_to_many - the join resource row is destroyed
|
||||
* has_many - the destination_field (on the related record) is set to `nil`
|
||||
* has_one - the destination_field (on the related record) is set to `nil`
|
||||
* belongs_to - the source_field (on this record) is set to `nil`
|
||||
* has_many - the destination_attribute (on the related record) is set to `nil`
|
||||
* has_one - the destination_attribute (on the related record) is set to `nil`
|
||||
* belongs_to - the source_attribute (on this record) is set to `nil`
|
||||
* `{:unrelate, :action_name}` - the record is unrelated using the provided update action. The action should be:
|
||||
* many_to_many - a destroy action on the join resource
|
||||
* has_many - an update action on the destination resource
|
||||
|
@ -2043,7 +2043,7 @@ defmodule Ash.Changeset do
|
|||
Enum.find_value(pkeys, fn pkey ->
|
||||
this_filter =
|
||||
pkey
|
||||
|> Enum.reject(&(&1.name == relationship.destination_field))
|
||||
|> Enum.reject(&(&1.name == relationship.destination_attribute))
|
||||
|> Enum.all?(fn key ->
|
||||
case fetch_identity_field(
|
||||
item,
|
||||
|
@ -2072,14 +2072,14 @@ defmodule Ash.Changeset do
|
|||
nil
|
||||
end
|
||||
|
||||
if Enum.any?(pkey, &(&1.name == relationship.destination_field)) &&
|
||||
if Enum.any?(pkey, &(&1.name == relationship.destination_attribute)) &&
|
||||
relationship.type in [:has_many, :has_one] do
|
||||
destination_value = Map.get(changeset.data, relationship.source_field)
|
||||
destination_value = Map.get(changeset.data, relationship.source_attribute)
|
||||
|
||||
Ash.Query.expr(
|
||||
^this_filter and
|
||||
(is_nil(ref(^relationship.destination_field, [])) or
|
||||
ref(^relationship.destination_field, []) == ^destination_value)
|
||||
(is_nil(ref(^relationship.destination_attribute, [])) or
|
||||
ref(^relationship.destination_attribute, []) == ^destination_value)
|
||||
)
|
||||
else
|
||||
this_filter
|
||||
|
@ -2172,9 +2172,9 @@ defmodule Ash.Changeset do
|
|||
end
|
||||
|
||||
defp fetch_identity_field(item, data, attribute, relationship) do
|
||||
if attribute.name == relationship.destination_field &&
|
||||
if attribute.name == relationship.destination_attribute &&
|
||||
relationship.type in [:has_many, :has_one] do
|
||||
{:ok, Map.get(data, relationship.source_field)}
|
||||
{:ok, Map.get(data, relationship.source_attribute)}
|
||||
else
|
||||
string_attribute = to_string(attribute.name)
|
||||
|
||||
|
|
|
@ -1354,8 +1354,8 @@ defmodule Ash.Filter do
|
|||
relationship.through
|
||||
|> Ash.Query.new(api)
|
||||
|> Ash.Query.do_filter([
|
||||
{relationship.destination_field_on_join_table,
|
||||
in: Enum.map(results, &Map.get(&1, relationship.destination_field))}
|
||||
{relationship.destination_attribute_on_join_resource,
|
||||
in: Enum.map(results, &Map.get(&1, relationship.destination_attribute))}
|
||||
])
|
||||
|> filter_related_in(
|
||||
Ash.Resource.Info.relationship(resource, join_relationship),
|
||||
|
@ -1429,9 +1429,9 @@ defmodule Ash.Filter do
|
|||
%Ref{
|
||||
relationship_path: path,
|
||||
resource: relationship.source,
|
||||
attribute: Ash.Resource.Info.attribute(relationship.source, relationship.source_field)
|
||||
attribute: Ash.Resource.Info.attribute(relationship.source, relationship.source_attribute)
|
||||
},
|
||||
Map.get(single_record, relationship.destination_field)
|
||||
Map.get(single_record, relationship.destination_attribute)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ defmodule Ash.Generator do
|
|||
resource
|
||||
|> Ash.Resource.Info.attributes()
|
||||
|> Enum.reject(fn attribute ->
|
||||
Enum.any?(relationships, &(&1.source_field == attribute.name))
|
||||
Enum.any?(relationships, &(&1.source_attribute == attribute.name))
|
||||
end)
|
||||
|> generate_attributes(generators, true, :create)
|
||||
end
|
||||
|
|
|
@ -18,9 +18,9 @@ defmodule Ash.Policy.Check.RelatingToActor do
|
|||
raise "Can only use `belongs_to` relationships in relating_to_actor checks"
|
||||
end
|
||||
|
||||
if Ash.Changeset.changing_attribute?(changeset, relationship.source_field) do
|
||||
Ash.Changeset.get_attribute(changeset, relationship.source_field) ==
|
||||
Map.get(actor, relationship.destination_field)
|
||||
if Ash.Changeset.changing_attribute?(changeset, relationship.source_attribute) do
|
||||
Ash.Changeset.get_attribute(changeset, relationship.source_attribute) ==
|
||||
Map.get(actor, relationship.destination_attribute)
|
||||
else
|
||||
false
|
||||
end
|
||||
|
|
|
@ -29,14 +29,14 @@ defmodule Ash.Query.Aggregate do
|
|||
def kinds, do: @kinds
|
||||
|
||||
def new(resource, name, kind, relationship, query, field, default \\ nil, filterable? \\ true) do
|
||||
field_type =
|
||||
attribute_type =
|
||||
if field do
|
||||
related = Ash.Resource.Info.related(resource, relationship)
|
||||
Ash.Resource.Info.attribute(related, field).type
|
||||
end
|
||||
|
||||
with :ok <- validate_path(resource, List.wrap(relationship)),
|
||||
{:ok, type} <- kind_to_type(kind, field_type),
|
||||
{:ok, type} <- kind_to_type(kind, attribute_type),
|
||||
{:ok, query} <- validate_query(query) do
|
||||
{:ok,
|
||||
%__MODULE__{
|
||||
|
@ -114,11 +114,11 @@ defmodule Ash.Query.Aggregate do
|
|||
end
|
||||
|
||||
@doc false
|
||||
def kind_to_type(:count, _field_type), do: {:ok, Ash.Type.Integer}
|
||||
def kind_to_type(:count, _attribute_type), do: {:ok, Ash.Type.Integer}
|
||||
def kind_to_type(kind, nil), do: {:error, "Must provide field type for #{kind}"}
|
||||
def kind_to_type(kind, field_type) when kind in [:first, :sum], do: {:ok, field_type}
|
||||
def kind_to_type(:list, field_type), do: {:ok, {:array, field_type}}
|
||||
def kind_to_type(kind, _field_type), do: {:error, "Invalid aggregate kind: #{kind}"}
|
||||
def kind_to_type(kind, attribute_type) when kind in [:first, :sum], do: {:ok, attribute_type}
|
||||
def kind_to_type(:list, attribute_type), do: {:ok, {:array, attribute_type}}
|
||||
def kind_to_type(kind, _attribute_type), do: {:error, "Invalid aggregate kind: #{kind}"}
|
||||
|
||||
def requests(initial_query, can_be_in_query?, authorizing?, calculations_in_query, request_path) do
|
||||
initial_query.aggregates
|
||||
|
|
|
@ -1644,7 +1644,7 @@ defmodule Ash.Query do
|
|||
|
||||
relationship ->
|
||||
cond do
|
||||
!selecting?(query, relationship.source_field) ->
|
||||
!selecting?(query, relationship.source_attribute) ->
|
||||
[
|
||||
{:error,
|
||||
"Cannot load a relationship if you are not selecting the source field of that relationship"}
|
||||
|
|
|
@ -155,8 +155,8 @@ defmodule Ash.Resource.Dsl do
|
|||
"""
|
||||
# In a resource called `Word`
|
||||
has_one :dictionary_entry, DictionaryEntry do
|
||||
source_field :text
|
||||
destination_field :word_text
|
||||
source_attribute :text
|
||||
destination_attribute :word_text
|
||||
end
|
||||
"""
|
||||
],
|
||||
|
@ -180,8 +180,8 @@ defmodule Ash.Resource.Dsl do
|
|||
"""
|
||||
# In a resource called `Word`
|
||||
has_many :definitions, DictionaryDefinition do
|
||||
source_field :text
|
||||
destination_field :word_text
|
||||
source_attribute :text
|
||||
destination_attribute :word_text
|
||||
end
|
||||
"""
|
||||
],
|
||||
|
@ -213,10 +213,10 @@ defmodule Ash.Resource.Dsl do
|
|||
# In a resource called `Word`
|
||||
many_to_many :books, Book do
|
||||
through BookWord
|
||||
source_field :text
|
||||
source_field_on_join_table :word_text
|
||||
destination_field :id
|
||||
destination_field_on_join_table :book_id
|
||||
source_attribute :text
|
||||
source_attribute_on_join_resource :word_text
|
||||
destination_attribute :id
|
||||
destination_attribute_on_join_resource :book_id
|
||||
end
|
||||
|
||||
# And in `BookWord` (the resource that defines the join table)
|
||||
|
@ -236,7 +236,7 @@ defmodule Ash.Resource.Dsl do
|
|||
describe: """
|
||||
Declares a belongs_to relationship. In a relational database, the foreign key would be on the *source* table.
|
||||
|
||||
This creates a field on the resource with the corresponding name and type, unless `define_field?: false` is provided.
|
||||
This creates a field on the resource with the corresponding name and type, unless `define_attribute?: false` is provided.
|
||||
""",
|
||||
links: [
|
||||
guides: [
|
||||
|
@ -247,8 +247,8 @@ defmodule Ash.Resource.Dsl do
|
|||
"""
|
||||
# In a resource called `Word`
|
||||
belongs_to :dictionary_entry, DictionaryEntry do
|
||||
source_field :text,
|
||||
destination_field :word_text
|
||||
source_attribute :text,
|
||||
destination_attribute :word_text
|
||||
end
|
||||
"""
|
||||
],
|
||||
|
@ -289,19 +289,19 @@ defmodule Ash.Resource.Dsl do
|
|||
|
||||
many_to_many :categories, MyApp.Category do
|
||||
through MyApp.PostCategory
|
||||
destination_field_on_join_table :category_id
|
||||
source_field_on_join_table :post_id
|
||||
destination_attribute_on_join_resource :category_id
|
||||
source_attribute_on_join_resource :post_id
|
||||
end
|
||||
end
|
||||
""",
|
||||
"""
|
||||
relationships do
|
||||
has_many :posts, MyApp.Post do
|
||||
destination_field :author_id
|
||||
destination_attribute :author_id
|
||||
end
|
||||
|
||||
has_many :composite_key_posts, MyApp.CompositeKeyPost do
|
||||
destination_field :author_id
|
||||
destination_attribute :author_id
|
||||
end
|
||||
end
|
||||
"""
|
||||
|
|
|
@ -56,12 +56,12 @@ defmodule Ash.Resource.Info do
|
|||
defp reverse_relationship?(rel, destination_rel) do
|
||||
rel.source == destination_rel.destination &&
|
||||
rel.destination == destination_rel.source &&
|
||||
rel.source_field == destination_rel.destination_field &&
|
||||
rel.destination_field == destination_rel.source_field &&
|
||||
Map.fetch(rel, :source_field_on_join_table) ==
|
||||
Map.fetch(destination_rel, :destination_field_on_join_table) &&
|
||||
Map.fetch(rel, :destination_field_on_join_table) ==
|
||||
Map.fetch(destination_rel, :source_field_on_join_table) &&
|
||||
rel.source_attribute == destination_rel.destination_attribute &&
|
||||
rel.destination_attribute == destination_rel.source_attribute &&
|
||||
Map.fetch(rel, :source_attribute_on_join_resource) ==
|
||||
Map.fetch(destination_rel, :destination_attribute_on_join_resource) &&
|
||||
Map.fetch(rel, :destination_attribute_on_join_resource) ==
|
||||
Map.fetch(destination_rel, :source_attribute_on_join_resource) &&
|
||||
is_nil(destination_rel.context) &&
|
||||
is_nil(rel.context)
|
||||
end
|
||||
|
|
|
@ -5,11 +5,11 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
:name,
|
||||
:destination,
|
||||
:primary_key?,
|
||||
:define_field?,
|
||||
:field_type,
|
||||
:destination_field,
|
||||
:define_attribute?,
|
||||
:attribute_type,
|
||||
:destination_attribute,
|
||||
:private?,
|
||||
:source_field,
|
||||
:source_attribute,
|
||||
:source,
|
||||
:read_action,
|
||||
:api,
|
||||
|
@ -22,7 +22,7 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
:context,
|
||||
:description,
|
||||
:attribute_writable?,
|
||||
validate_destination_field?: true,
|
||||
validate_destination_attribute?: true,
|
||||
cardinality: :one,
|
||||
type: :belongs_to
|
||||
]
|
||||
|
@ -38,13 +38,13 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
destination: Ash.Resource.t(),
|
||||
required?: boolean,
|
||||
primary_key?: boolean,
|
||||
define_field?: boolean,
|
||||
field_type: term,
|
||||
define_attribute?: boolean,
|
||||
attribute_type: term,
|
||||
writable?: boolean,
|
||||
attribute_writable?: boolean,
|
||||
destination_field: atom,
|
||||
destination_attribute: atom,
|
||||
private?: boolean,
|
||||
source_field: atom | nil,
|
||||
source_attribute: atom | nil,
|
||||
description: String.t()
|
||||
}
|
||||
|
||||
|
@ -53,8 +53,8 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
alias Spark.OptionsHelpers
|
||||
|
||||
@global_opts shared_options()
|
||||
|> OptionsHelpers.set_default!(:destination_field, :id)
|
||||
|> OptionsHelpers.append_doc!(:source_field, "Defaults to <name>_id")
|
||||
|> OptionsHelpers.set_default!(:destination_attribute, :id)
|
||||
|> OptionsHelpers.append_doc!(:source_attribute, "Defaults to <name>_id")
|
||||
|> Keyword.delete(:could_be_related_at_creation?)
|
||||
|
||||
@opt_schema Spark.OptionsHelpers.merge_schemas(
|
||||
|
@ -87,7 +87,7 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
Whether the generated attribute will be marked as public & writable.
|
||||
"""
|
||||
],
|
||||
define_field?: [
|
||||
define_attribute?: [
|
||||
type: :boolean,
|
||||
default: true,
|
||||
links: [
|
||||
|
@ -96,7 +96,7 @@ defmodule Ash.Resource.Relationships.BelongsTo do
|
|||
doc:
|
||||
"If set to `false` an attribute is not created on the resource for this relationship, and one must be manually added in `attributes`, invalidating many other options."
|
||||
],
|
||||
field_type: [
|
||||
attribute_type: [
|
||||
type: :any,
|
||||
links: [
|
||||
modules: [
|
||||
|
|
|
@ -3,9 +3,9 @@ defmodule Ash.Resource.Relationships.HasMany do
|
|||
defstruct [
|
||||
:name,
|
||||
:destination,
|
||||
:destination_field,
|
||||
:destination_attribute,
|
||||
:private?,
|
||||
:source_field,
|
||||
:source_attribute,
|
||||
:source,
|
||||
:context,
|
||||
:description,
|
||||
|
@ -17,9 +17,9 @@ defmodule Ash.Resource.Relationships.HasMany do
|
|||
:manual,
|
||||
:api,
|
||||
:writable?,
|
||||
no_fields?: false,
|
||||
no_attributes?: false,
|
||||
could_be_related_at_creation?: false,
|
||||
validate_destination_field?: true,
|
||||
validate_destination_attribute?: true,
|
||||
cardinality: :many,
|
||||
type: :has_many
|
||||
]
|
||||
|
@ -30,14 +30,14 @@ defmodule Ash.Resource.Relationships.HasMany do
|
|||
source: Ash.Resource.t(),
|
||||
read_action: atom,
|
||||
filter: Ash.Filter.t() | nil,
|
||||
no_fields?: boolean,
|
||||
no_attributes?: boolean,
|
||||
name: atom,
|
||||
type: Ash.Type.t(),
|
||||
writable?: boolean,
|
||||
destination: Ash.Resource.t(),
|
||||
destination_field: atom,
|
||||
destination_attribute: atom,
|
||||
private?: boolean,
|
||||
source_field: atom,
|
||||
source_attribute: atom,
|
||||
description: String.t(),
|
||||
manual: atom | {atom, Keyword.t()} | nil
|
||||
}
|
||||
|
@ -46,12 +46,12 @@ defmodule Ash.Resource.Relationships.HasMany do
|
|||
alias Spark.OptionsHelpers
|
||||
|
||||
@global_opts shared_options()
|
||||
|> OptionsHelpers.set_default!(:source_field, :id)
|
||||
|> OptionsHelpers.set_default!(:source_attribute, :id)
|
||||
|
||||
@opt_schema Spark.OptionsHelpers.merge_schemas(
|
||||
[
|
||||
manual(),
|
||||
no_fields()
|
||||
no_attributes()
|
||||
],
|
||||
@global_opts,
|
||||
"Relationship Options"
|
||||
|
|
|
@ -5,9 +5,9 @@ defmodule Ash.Resource.Relationships.HasOne do
|
|||
:name,
|
||||
:source,
|
||||
:destination,
|
||||
:destination_field,
|
||||
:destination_attribute,
|
||||
:private?,
|
||||
:source_field,
|
||||
:source_attribute,
|
||||
:allow_orphans?,
|
||||
:context,
|
||||
:description,
|
||||
|
@ -19,9 +19,9 @@ defmodule Ash.Resource.Relationships.HasOne do
|
|||
:violation_message,
|
||||
:manual,
|
||||
:writable?,
|
||||
no_fields?: false,
|
||||
no_attributes?: false,
|
||||
could_be_related_at_creation?: false,
|
||||
validate_destination_field?: true,
|
||||
validate_destination_attribute?: true,
|
||||
cardinality: :one,
|
||||
type: :has_one,
|
||||
required?: false
|
||||
|
@ -33,14 +33,14 @@ defmodule Ash.Resource.Relationships.HasOne do
|
|||
source: Ash.Resource.t(),
|
||||
name: atom,
|
||||
read_action: atom,
|
||||
no_fields?: boolean,
|
||||
no_attributes?: boolean,
|
||||
writable?: boolean,
|
||||
type: Ash.Type.t(),
|
||||
filter: Ash.Filter.t() | nil,
|
||||
destination: Ash.Resource.t(),
|
||||
destination_field: atom,
|
||||
destination_attribute: atom,
|
||||
private?: boolean,
|
||||
source_field: atom,
|
||||
source_attribute: atom,
|
||||
allow_orphans?: boolean,
|
||||
description: String.t(),
|
||||
manual: atom | {atom, Keyword.t()} | nil
|
||||
|
@ -50,10 +50,10 @@ defmodule Ash.Resource.Relationships.HasOne do
|
|||
alias Spark.OptionsHelpers
|
||||
|
||||
@global_opts shared_options()
|
||||
|> OptionsHelpers.set_default!(:source_field, :id)
|
||||
|> OptionsHelpers.set_default!(:source_attribute, :id)
|
||||
|
||||
@opt_schema Spark.OptionsHelpers.merge_schemas(
|
||||
[manual(), no_fields()] ++
|
||||
[manual(), no_attributes()] ++
|
||||
[
|
||||
required?: [
|
||||
type: :boolean,
|
||||
|
|
|
@ -5,10 +5,10 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
:source,
|
||||
:through,
|
||||
:destination,
|
||||
:source_field,
|
||||
:destination_field,
|
||||
:source_field_on_join_table,
|
||||
:destination_field_on_join_table,
|
||||
:source_attribute,
|
||||
:destination_attribute,
|
||||
:source_attribute_on_join_resource,
|
||||
:destination_attribute_on_join_resource,
|
||||
:join_relationship,
|
||||
:not_found_message,
|
||||
:violation_message,
|
||||
|
@ -21,7 +21,7 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
:filter,
|
||||
:has_many,
|
||||
could_be_related_at_creation?: false,
|
||||
validate_destination_field?: true,
|
||||
validate_destination_attribute?: true,
|
||||
cardinality: :many,
|
||||
type: :many_to_many
|
||||
]
|
||||
|
@ -38,10 +38,10 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
through: Ash.Resource.t(),
|
||||
destination: Ash.Resource.t(),
|
||||
join_relationship: atom,
|
||||
source_field: atom,
|
||||
destination_field: atom,
|
||||
source_field_on_join_table: atom,
|
||||
destination_field_on_join_table: atom,
|
||||
source_attribute: atom,
|
||||
destination_attribute: atom,
|
||||
source_attribute_on_join_resource: atom,
|
||||
destination_attribute_on_join_resource: atom,
|
||||
description: String.t()
|
||||
}
|
||||
|
||||
|
@ -49,12 +49,12 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
alias Spark.OptionsHelpers
|
||||
|
||||
@global_opts shared_options()
|
||||
|> OptionsHelpers.set_default!(:destination_field, :id)
|
||||
|> OptionsHelpers.set_default!(:source_field, :id)
|
||||
|> OptionsHelpers.set_default!(:destination_attribute, :id)
|
||||
|> OptionsHelpers.set_default!(:source_attribute, :id)
|
||||
|
||||
@opt_schema Spark.OptionsHelpers.merge_schemas(
|
||||
[
|
||||
source_field_on_join_table: [
|
||||
source_attribute_on_join_resource: [
|
||||
type: :atom,
|
||||
required: true,
|
||||
links: [
|
||||
|
@ -63,9 +63,9 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
]
|
||||
],
|
||||
doc:
|
||||
"The attribute on the join resource that should line up with `source_field` on this resource."
|
||||
"The attribute on the join resource that should line up with `source_attribute` on this resource."
|
||||
],
|
||||
destination_field_on_join_table: [
|
||||
destination_attribute_on_join_resource: [
|
||||
type: :atom,
|
||||
required: true,
|
||||
links: [
|
||||
|
@ -74,7 +74,7 @@ defmodule Ash.Resource.Relationships.ManyToMany do
|
|||
]
|
||||
],
|
||||
doc:
|
||||
"The attribute on the join resource that should line up with `destination_field` on the related resource."
|
||||
"The attribute on the join resource that should line up with `destination_attribute` on the related resource."
|
||||
],
|
||||
through: [
|
||||
type: Ash.OptionsHelpers.ash_resource(),
|
||||
|
|
|
@ -19,7 +19,7 @@ defmodule Ash.Resource.Relationships.SharedOptions do
|
|||
modules: ["ash:guide:Documentation"]
|
||||
]
|
||||
],
|
||||
destination_field: [
|
||||
destination_attribute: [
|
||||
type: :atom,
|
||||
links: [
|
||||
dsls: [
|
||||
|
@ -27,16 +27,16 @@ defmodule Ash.Resource.Relationships.SharedOptions do
|
|||
]
|
||||
],
|
||||
doc:
|
||||
"The attribute on the related resource that should match the `source_field` configured on this resource."
|
||||
"The attribute on the related resource that should match the `source_attribute` configured on this resource."
|
||||
],
|
||||
validate_destination_field?: [
|
||||
validate_destination_attribute?: [
|
||||
type: :boolean,
|
||||
default: true,
|
||||
doc:
|
||||
"Whether or not to validate that the destination field exists on the destination resource",
|
||||
links: []
|
||||
],
|
||||
source_field: [
|
||||
source_attribute: [
|
||||
type: :atom,
|
||||
links: [
|
||||
dsls: [
|
||||
|
@ -44,7 +44,7 @@ defmodule Ash.Resource.Relationships.SharedOptions do
|
|||
]
|
||||
],
|
||||
doc:
|
||||
"The field on this resource that should match the `destination_field` on the related resource."
|
||||
"The field on this resource that should match the `destination_attribute` on the related resource."
|
||||
],
|
||||
relationship_context: [
|
||||
type: :any,
|
||||
|
@ -134,18 +134,18 @@ defmodule Ash.Resource.Relationships.SharedOptions do
|
|||
@shared_options
|
||||
end
|
||||
|
||||
def no_fields do
|
||||
{:no_fields?,
|
||||
def no_attributes do
|
||||
{:no_attributes?,
|
||||
[
|
||||
type: :boolean,
|
||||
links: [],
|
||||
doc: """
|
||||
If true, all existing entities are considered related, i.e this relationship is not based on any fields, and `source_field` and
|
||||
`destination_field` are ignored.
|
||||
If true, all existing entities are considered related, i.e this relationship is not based on any fields, and `source_attribute` and
|
||||
`destination_attribute` are ignored.
|
||||
|
||||
This can be very useful when combined with multitenancy. Specifically, if you have a tenant resource like `Organization`,
|
||||
you can use `no_fields?` to do things like `has_many :employees, Employee, no_fields?: true`, which lets you avoid having an
|
||||
unnecessary `organization_id` field on `Employee`. The same works in reverse: `has_one :organization, Organization, no_fields?: true`
|
||||
you can use `no_attributes?` to do things like `has_many :employees, Employee, no_attributes?: true`, which lets you avoid having an
|
||||
unnecessary `organization_id` field on `Employee`. The same works in reverse: `has_one :organization, Organization, no_attributes?: true`
|
||||
allows relating the employee to their organization.
|
||||
|
||||
Some important caveats here:
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule Ash.Resource.Transformers.BelongsToAttribute do
|
||||
@moduledoc """
|
||||
Creates the attribute for belongs_to relationships that have `define_field?: true`
|
||||
Creates the attribute for belongs_to relationships that have `define_attribute?: true`
|
||||
"""
|
||||
use Spark.Dsl.Transformer
|
||||
|
||||
|
@ -12,17 +12,17 @@ defmodule Ash.Resource.Transformers.BelongsToAttribute do
|
|||
def transform(resource, dsl_state) do
|
||||
dsl_state
|
||||
|> Transformer.get_entities([:relationships])
|
||||
|> Enum.filter(&(&1.type == :belongs_to && &1.define_field?))
|
||||
|> Enum.filter(&(&1.type == :belongs_to && &1.define_attribute?))
|
||||
|> Enum.reject(fn relationship ->
|
||||
dsl_state
|
||||
|> Transformer.get_entities([:attributes])
|
||||
|> Enum.find(&(Map.get(&1, :name) == relationship.source_field))
|
||||
|> Enum.find(&(Map.get(&1, :name) == relationship.source_attribute))
|
||||
end)
|
||||
|> Enum.reduce_while({:ok, dsl_state}, fn relationship, {:ok, dsl_state} ->
|
||||
entity =
|
||||
Transformer.build_entity(@extension, [:attributes], :attribute,
|
||||
name: relationship.source_field,
|
||||
type: relationship.field_type || :uuid,
|
||||
name: relationship.source_attribute,
|
||||
type: relationship.attribute_type || :uuid,
|
||||
allow_nil?:
|
||||
if relationship.primary_key? do
|
||||
false
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
defmodule Ash.Resource.Transformers.BelongsToSourceField do
|
||||
@moduledoc """
|
||||
Sets the default `source_field` for belongs_to attributes
|
||||
Sets the default `source_attribute` for belongs_to attributes
|
||||
"""
|
||||
use Spark.Dsl.Transformer
|
||||
|
||||
|
@ -11,13 +11,13 @@ defmodule Ash.Resource.Transformers.BelongsToSourceField do
|
|||
dsl_state
|
||||
|> Transformer.get_entities([:relationships])
|
||||
|> Enum.filter(&(&1.type == :belongs_to))
|
||||
|> Enum.reject(& &1.source_field)
|
||||
|> Enum.reject(& &1.source_attribute)
|
||||
|> Enum.reduce({:ok, dsl_state}, fn relationship, {:ok, dsl_state} ->
|
||||
new_dsl_state =
|
||||
Transformer.replace_entity(
|
||||
dsl_state,
|
||||
[:relationships],
|
||||
%{relationship | source_field: :"#{relationship.name}_id"},
|
||||
%{relationship | source_attribute: :"#{relationship.name}_id"},
|
||||
&(&1.name == relationship.name)
|
||||
)
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ defmodule Ash.Resource.Transformers.CreateJoinRelationship do
|
|||
[
|
||||
name: relationship.join_relationship,
|
||||
destination: relationship.through,
|
||||
destination_field: relationship.source_field_on_join_table,
|
||||
destination_attribute: relationship.source_attribute_on_join_resource,
|
||||
api: relationship.api,
|
||||
source_field: relationship.source_field,
|
||||
source_attribute: relationship.source_attribute,
|
||||
private?: true
|
||||
]
|
||||
|> add_messages(relationship)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
defmodule Ash.Resource.Transformers.HasDestinationField do
|
||||
@moduledoc "Guesses the `destination_field` for has many and has one relationships unless provided"
|
||||
@moduledoc "Guesses the `destination_attribute` for has many and has one relationships unless provided"
|
||||
use Spark.Dsl.Transformer
|
||||
|
||||
alias Spark.Dsl.Transformer
|
||||
|
@ -9,9 +9,9 @@ defmodule Ash.Resource.Transformers.HasDestinationField do
|
|||
dsl_state
|
||||
|> Transformer.get_entities([:relationships])
|
||||
|> Enum.reduce(dsl_state, fn
|
||||
%{type: type, destination_field: nil} = relationship, dsl_state
|
||||
%{type: type, destination_attribute: nil} = relationship, dsl_state
|
||||
when type in [:has_many, :has_one] ->
|
||||
new_relationship = %{relationship | destination_field: resource_id_field(resource)}
|
||||
new_relationship = %{relationship | destination_attribute: resource_id_field(resource)}
|
||||
|
||||
Transformer.replace_entity(
|
||||
dsl_state,
|
||||
|
|
|
@ -17,21 +17,21 @@ defmodule Ash.Resource.Transformers.ValidateRelationshipAttributes do
|
|||
resource
|
||||
|> Ash.Resource.Info.relationships()
|
||||
|> Enum.reject(fn relationship ->
|
||||
Map.get(relationship, :manual) || Map.get(relationship, :no_fields?)
|
||||
Map.get(relationship, :manual) || Map.get(relationship, :no_attributes?)
|
||||
end)
|
||||
|> Enum.filter(& &1.validate_destination_field?)
|
||||
|> Enum.filter(& &1.validate_destination_attribute?)
|
||||
|> Enum.each(&validate_relationship(&1, attribute_names, resource))
|
||||
|
||||
{:ok, dsl}
|
||||
end
|
||||
|
||||
defp validate_relationship(relationship, attribute_names, resource) do
|
||||
unless relationship.source_field in attribute_names do
|
||||
unless relationship.source_attribute in attribute_names do
|
||||
raise Spark.Error.DslError,
|
||||
module: resource,
|
||||
path: [:relationships, relationship.name],
|
||||
message:
|
||||
"Relationship `#{relationship.name}` expects source field `#{relationship.source_field}` to be defined"
|
||||
"Relationship `#{relationship.name}` expects source field `#{relationship.source_attribute}` to be defined"
|
||||
end
|
||||
|
||||
if Code.ensure_loaded?(relationship.destination) do
|
||||
|
@ -42,20 +42,20 @@ defmodule Ash.Resource.Transformers.ValidateRelationshipAttributes do
|
|||
|> Ash.Resource.Info.attributes()
|
||||
|> Enum.map(& &1.name)
|
||||
|
||||
unless relationship.source_field_on_join_table in through_attributes do
|
||||
unless relationship.source_attribute_on_join_resource in through_attributes do
|
||||
raise Spark.Error.DslError,
|
||||
module: resource,
|
||||
path: [:relationships, relationship.name],
|
||||
message:
|
||||
"Relationship `#{relationship.name}` expects source field on join table `#{relationship.source_field_on_join_table}` to be defined on #{inspect(relationship.through)}"
|
||||
"Relationship `#{relationship.name}` expects source field on join table `#{relationship.source_attribute_on_join_resource}` to be defined on #{inspect(relationship.through)}"
|
||||
end
|
||||
|
||||
unless relationship.destination_field_on_join_table in through_attributes do
|
||||
unless relationship.destination_attribute_on_join_resource in through_attributes do
|
||||
raise Spark.Error.DslError,
|
||||
module: resource,
|
||||
path: [:relationships, relationship.name],
|
||||
message:
|
||||
"Relationship `#{relationship.name}` expects destination field on join table `#{relationship.destination_field_on_join_table}` to be defined on #{inspect(relationship.through)}"
|
||||
"Relationship `#{relationship.name}` expects destination field on join table `#{relationship.destination_attribute_on_join_resource}` to be defined on #{inspect(relationship.through)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -65,12 +65,12 @@ defmodule Ash.Resource.Transformers.ValidateRelationshipAttributes do
|
|||
|> Ash.Resource.Info.attributes()
|
||||
|> Enum.map(& &1.name)
|
||||
|
||||
unless relationship.destination_field in destination_attributes do
|
||||
unless relationship.destination_attribute in destination_attributes do
|
||||
raise Spark.Error.DslError,
|
||||
module: resource,
|
||||
path: [:relationships, relationship.name],
|
||||
message:
|
||||
"Relationship `#{relationship.name}` expects destination field `#{relationship.destination_field}` to be defined on #{inspect(relationship.destination)}"
|
||||
"Relationship `#{relationship.name}` expects destination field `#{relationship.destination_attribute}` to be defined on #{inspect(relationship.destination)}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ defmodule Ash.Resource.Validation do
|
|||
:validation,
|
||||
:module,
|
||||
:opts,
|
||||
:expensive?,
|
||||
:only_when_valid?,
|
||||
:description,
|
||||
:message,
|
||||
:before_action?,
|
||||
|
@ -55,7 +55,7 @@ defmodule Ash.Resource.Validation do
|
|||
validation: {atom(), list(atom())},
|
||||
module: atom(),
|
||||
opts: list(atom()),
|
||||
expensive?: boolean(),
|
||||
only_when_valid?: boolean(),
|
||||
description: String.t() | nil,
|
||||
where: list({atom(), list(atom())}),
|
||||
on: list(atom())
|
||||
|
@ -97,12 +97,12 @@ defmodule Ash.Resource.Validation do
|
|||
Many validations don't make sense in the context of deletion, so by default it is left out of the list.
|
||||
"""
|
||||
],
|
||||
expensive?: [
|
||||
only_when_valid?: [
|
||||
type: :boolean,
|
||||
default: false,
|
||||
links: [],
|
||||
doc:
|
||||
"If a validation is expensive, it won't be run on invalid changes. All inexpensive validations are always run, to provide informative errors."
|
||||
"If the validation should only run on valid changes. Useful for expensive validations or validations that depend on valid data."
|
||||
],
|
||||
message: [
|
||||
type: :string,
|
||||
|
|
|
@ -38,8 +38,8 @@ defmodule Ash.Resource.Validation.Changing do
|
|||
)}
|
||||
end
|
||||
|
||||
%{type: :belongs_to, source_field: source_field} = relationship ->
|
||||
if Ash.Changeset.changing_attribute?(changeset, source_field) ||
|
||||
%{type: :belongs_to, source_attribute: source_attribute} = relationship ->
|
||||
if Ash.Changeset.changing_attribute?(changeset, source_attribute) ||
|
||||
Ash.Changeset.changing_relationship?(changeset, relationship.name) do
|
||||
:ok
|
||||
else
|
||||
|
|
|
@ -123,8 +123,8 @@ defmodule Ash.Seed do
|
|||
|
||||
%{
|
||||
type: :belongs_to,
|
||||
source_field: source_field,
|
||||
destination_field: destination_field,
|
||||
source_attribute: source_attribute,
|
||||
destination_attribute: destination_attribute,
|
||||
destination: destination,
|
||||
name: name
|
||||
} ->
|
||||
|
@ -133,8 +133,8 @@ defmodule Ash.Seed do
|
|||
|
||||
changeset
|
||||
|> Ash.Changeset.force_change_attribute(
|
||||
source_field,
|
||||
Map.get(related, destination_field)
|
||||
source_attribute,
|
||||
Map.get(related, destination_attribute)
|
||||
)
|
||||
|> callback.()
|
||||
|> case do
|
||||
|
@ -148,8 +148,8 @@ defmodule Ash.Seed do
|
|||
|
||||
%{
|
||||
type: :has_many,
|
||||
source_field: source_field,
|
||||
destination_field: destination_field,
|
||||
source_attribute: source_attribute,
|
||||
destination_attribute: destination_attribute,
|
||||
destination: destination,
|
||||
name: name
|
||||
} ->
|
||||
|
@ -161,8 +161,8 @@ defmodule Ash.Seed do
|
|||
&update_or_seed!(
|
||||
&1,
|
||||
destination,
|
||||
Map.get(result, source_field),
|
||||
destination_field
|
||||
Map.get(result, source_attribute),
|
||||
destination_attribute
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -171,8 +171,8 @@ defmodule Ash.Seed do
|
|||
|
||||
%{
|
||||
type: :has_one,
|
||||
source_field: source_field,
|
||||
destination_field: destination_field,
|
||||
source_attribute: source_attribute,
|
||||
destination_attribute: destination_attribute,
|
||||
destination: destination,
|
||||
name: name
|
||||
} ->
|
||||
|
@ -182,8 +182,8 @@ defmodule Ash.Seed do
|
|||
update_or_seed!(
|
||||
value,
|
||||
destination,
|
||||
Map.get(result, source_field),
|
||||
destination_field
|
||||
Map.get(result, source_attribute),
|
||||
destination_attribute
|
||||
)
|
||||
|
||||
{:ok, Map.put(result, name, related)}
|
||||
|
@ -194,11 +194,11 @@ defmodule Ash.Seed do
|
|||
|
||||
%{
|
||||
type: :many_to_many,
|
||||
source_field: source_field,
|
||||
source_field_on_join_table: source_field_on_join_table,
|
||||
destination_field_on_join_table: destination_field_on_join_table,
|
||||
source_attribute: source_attribute,
|
||||
source_attribute_on_join_resource: source_attribute_on_join_resource,
|
||||
destination_attribute_on_join_resource: destination_attribute_on_join_resource,
|
||||
join_relationship: join_relationship,
|
||||
destination_field: destination_field,
|
||||
destination_attribute: destination_attribute,
|
||||
destination: destination,
|
||||
through: through,
|
||||
name: name
|
||||
|
@ -209,8 +209,9 @@ defmodule Ash.Seed do
|
|||
through =
|
||||
Enum.map(related, fn related ->
|
||||
seed!(through, %{
|
||||
source_field_on_join_table => Map.get(result, source_field),
|
||||
destination_field_on_join_table => Map.get(related, destination_field)
|
||||
source_attribute_on_join_resource => Map.get(result, source_attribute),
|
||||
destination_attribute_on_join_resource =>
|
||||
Map.get(related, destination_attribute)
|
||||
})
|
||||
end)
|
||||
|
||||
|
|
|
@ -169,9 +169,9 @@ defmodule Ash.SatSolver do
|
|||
when path != [] do
|
||||
with relationship when not is_nil(relationship) <-
|
||||
Ash.Resource.Info.relationship(resource, path),
|
||||
true <- attribute.name == relationship.destination_field,
|
||||
true <- attribute.name == relationship.destination_attribute,
|
||||
new_attribute when not is_nil(new_attribute) <-
|
||||
Ash.Resource.Info.attribute(relationship.source, relationship.source_field) do
|
||||
Ash.Resource.Info.attribute(relationship.source, relationship.source_attribute) do
|
||||
%{
|
||||
ref
|
||||
| relationship_path: :lists.droplast(path),
|
||||
|
@ -317,11 +317,11 @@ defmodule Ash.SatSolver do
|
|||
|
||||
true ->
|
||||
comparison_keys = [
|
||||
:source_field,
|
||||
:destination_field,
|
||||
:source_field_on_join_table,
|
||||
:destination_field_on_join_table,
|
||||
:destination_field,
|
||||
:source_attribute,
|
||||
:destination_attribute,
|
||||
:source_attribute_on_join_resource,
|
||||
:destination_attribute_on_join_resource,
|
||||
:destination_attribute,
|
||||
:destination
|
||||
]
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ a `Tweet` belongs to a specific `User`.
|
|||
```elixir
|
||||
# in lib/my_app/resources/user.ex
|
||||
relationships do
|
||||
has_many :tweets, MyApp.Tweet, destination_field: :user_id
|
||||
has_many :tweets, MyApp.Tweet, destination_attribute: :user_id
|
||||
end
|
||||
|
||||
# in lib/my_app/resources/tweet.ex
|
||||
|
|
|
@ -7,6 +7,18 @@
|
|||
The DSL tooling has been moved out of the Ash name space and into a more generalized tool called `Spark`. If you have written your own extensions, you will need
|
||||
to refer to those modules. They are all the same, they simply have different names. You will get compiler errors/warnings on the modules you need to change, for example: `Ash.Dsl` -> `Spark.Dsl` and `Ash.Dsl.Transformer` -> `Spark.Dsl.Transformer`. One exception, `Ash.Error.Dsl.DslError`, has been changed to `Spark.Error.DslError`.
|
||||
|
||||
## DSL name changes
|
||||
|
||||
These should all be straight forward enough to do a simple find and replace in your resources.
|
||||
|
||||
- `source_field` -> `source_attribute`
|
||||
- `destination_field` -> `destination_attribute`
|
||||
- `define_field?` -> `define_attribute?`
|
||||
- `field_type` -> `attribute_type`
|
||||
- `source_field_on_join_table` -> `source_attribute_on_join_resource`
|
||||
- `destination_field_on_join_table` -> `destination_attribute_on_join_resource`
|
||||
- `no_fields?` -> `no_attributes?`
|
||||
|
||||
## Upgrading to 1.53
|
||||
|
||||
### Default actions
|
||||
|
|
|
@ -24,18 +24,18 @@ defmodule Ash.Test.Actions.AsyncLoadTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.Actions.AsyncLoadTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.Actions.AsyncLoadTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_many :authorized_actor_posts, Ash.Test.Actions.AsyncLoadTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
read_action: :authorized_actor
|
||||
|
||||
has_many :authorized_context_posts, Ash.Test.Actions.AsyncLoadTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
read_action: :authorized_context
|
||||
|
||||
has_one :latest_post, Ash.Test.Actions.AsyncLoadTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
sort: [inserted_at: :desc]
|
||||
end
|
||||
end
|
||||
|
@ -95,8 +95,8 @@ defmodule Ash.Test.Actions.AsyncLoadTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.Actions.AsyncLoadTest.Category,
|
||||
through: Ash.Test.Actions.AsyncLoadTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
|
||||
policies do
|
||||
|
@ -147,8 +147,8 @@ defmodule Ash.Test.Actions.AsyncLoadTest do
|
|||
relationships do
|
||||
many_to_many :posts, Post,
|
||||
through: PostCategory,
|
||||
destination_field_on_join_table: :post_id,
|
||||
source_field_on_join_table: :category_id
|
||||
destination_attribute_on_join_resource: :post_id,
|
||||
source_attribute_on_join_resource: :category_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -147,9 +147,9 @@ defmodule Ash.Test.Actions.CreateTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_one(:profile, Profile, destination_field: :author_id)
|
||||
has_one(:profile, Profile, destination_attribute: :author_id)
|
||||
|
||||
has_many(:posts, Ash.Test.Actions.CreateTest.Post, destination_field: :author_id)
|
||||
has_many(:posts, Ash.Test.Actions.CreateTest.Post, destination_attribute: :author_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -255,8 +255,8 @@ defmodule Ash.Test.Actions.CreateTest do
|
|||
|
||||
many_to_many(:related_posts, __MODULE__,
|
||||
through: PostLink,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,9 +64,9 @@ defmodule Ash.Test.Actions.DestroyTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_one :profile, Profile, destination_field: :author_id
|
||||
has_one :profile, Profile, destination_attribute: :author_id
|
||||
|
||||
has_many :posts, Ash.Test.Actions.DestroyTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.Actions.DestroyTest.Post, destination_attribute: :author_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.Actions.LoadTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.Actions.LoadTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_one :latest_post, Ash.Test.Actions.LoadTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
sort: [inserted_at: :desc]
|
||||
end
|
||||
end
|
||||
|
@ -92,8 +92,8 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.Actions.LoadTest.Category,
|
||||
through: Ash.Test.Actions.LoadTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -138,8 +138,8 @@ defmodule Ash.Test.Actions.LoadTest do
|
|||
relationships do
|
||||
many_to_many :posts, Post,
|
||||
through: PostCategory,
|
||||
destination_field_on_join_table: :post_id,
|
||||
source_field_on_join_table: :category_id
|
||||
destination_attribute_on_join_resource: :post_id,
|
||||
source_attribute_on_join_resource: :category_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -27,8 +27,10 @@ defmodule Ash.Actions.MultitenancyTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Actions.MultitenancyTest.Post, destination_field: :author_id
|
||||
has_many :comments, Ash.Actions.MultitenancyTest.Comment, destination_field: :commenter_id
|
||||
has_many :posts, Ash.Actions.MultitenancyTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_many :comments, Ash.Actions.MultitenancyTest.Comment,
|
||||
destination_attribute: :commenter_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -51,7 +53,7 @@ defmodule Ash.Actions.MultitenancyTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :comments, Ash.Actions.MultitenancyTest.Comment, destination_field: :post_id
|
||||
has_many :comments, Ash.Actions.MultitenancyTest.Comment, destination_attribute: :post_id
|
||||
belongs_to :author, User
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,7 +27,7 @@ defmodule Ash.Actions.PaginationTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
belongs_to :user, Ash.Actions.PaginationTest.User, define_field?: false
|
||||
belongs_to :user, Ash.Actions.PaginationTest.User, define_attribute?: false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ defmodule Ash.Test.Actions.ReadTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.Actions.ReadTest.Post, destination_field: :author1_id
|
||||
has_many :posts, Ash.Test.Actions.ReadTest.Post, destination_attribute: :author1_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -119,9 +119,9 @@ defmodule Ash.Test.Actions.UpdateTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_one :profile, Profile, destination_field: :author_id
|
||||
has_one :profile, Profile, destination_attribute: :author_id
|
||||
|
||||
has_many :posts, Ash.Test.Actions.UpdateTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.Actions.UpdateTest.Post, destination_attribute: :author_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -175,8 +175,8 @@ defmodule Ash.Test.Actions.UpdateTest do
|
|||
|
||||
many_to_many :related_posts, __MODULE__,
|
||||
through: PostLink,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -47,8 +47,8 @@ defmodule Ash.Test.Changeset.ChangesetTest do
|
|||
relationships do
|
||||
many_to_many :posts, Ash.Test.Changeset.ChangesetTest.Post,
|
||||
through: Ash.Test.Changeset.ChangesetTest.PostCategory,
|
||||
destination_field_on_join_table: :post_id,
|
||||
source_field_on_join_table: :category_id
|
||||
destination_attribute_on_join_resource: :post_id,
|
||||
source_attribute_on_join_resource: :category_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,13 +74,13 @@ defmodule Ash.Test.Changeset.ChangesetTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.Changeset.ChangesetTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.Changeset.ChangesetTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_many :unique_posts, Ash.Test.Changeset.ChangesetTest.UniqueNamePerAuthor,
|
||||
destination_field: :author_id
|
||||
destination_attribute: :author_id
|
||||
|
||||
has_many :composite_key_posts, Ash.Test.Changeset.ChangesetTest.CompositeKeyPost,
|
||||
destination_field: :author_id
|
||||
destination_attribute: :author_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -128,8 +128,8 @@ defmodule Ash.Test.Changeset.ChangesetTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.Changeset.ChangesetTest.Category,
|
||||
through: Ash.Test.Changeset.ChangesetTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -157,8 +157,8 @@ defmodule Ash.Test.Changeset.ChangesetTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.Changeset.ChangesetTest.Category,
|
||||
through: Ash.Test.Changeset.ChangesetTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -190,8 +190,8 @@ defmodule Ash.Test.Changeset.ChangesetTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.Changeset.ChangesetTest.Category,
|
||||
through: Ash.Test.Changeset.ChangesetTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -50,13 +50,15 @@ defmodule Ash.Test.Filter.FilterInteractionTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many(:posts, Ash.Test.Filter.FilterInteractionTest.Post, destination_field: :author_id)
|
||||
|
||||
has_many(:second_posts, Ash.Test.Filter.FilterInteractionTest.Post,
|
||||
destination_field: :author_id
|
||||
has_many(:posts, Ash.Test.Filter.FilterInteractionTest.Post,
|
||||
destination_attribute: :author_id
|
||||
)
|
||||
|
||||
has_one(:profile, Profile, destination_field: :user_id)
|
||||
has_many(:second_posts, Ash.Test.Filter.FilterInteractionTest.Post,
|
||||
destination_attribute: :author_id
|
||||
)
|
||||
|
||||
has_one(:profile, Profile, destination_attribute: :user_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -98,14 +100,14 @@ defmodule Ash.Test.Filter.FilterInteractionTest do
|
|||
|
||||
relationships do
|
||||
belongs_to(:author, User,
|
||||
destination_field: :id,
|
||||
source_field: :author_id
|
||||
destination_attribute: :id,
|
||||
source_attribute: :author_id
|
||||
)
|
||||
|
||||
many_to_many(:related_posts, __MODULE__,
|
||||
through: PostLink,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -64,11 +64,11 @@ defmodule Ash.Test.Filter.FilterTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.Filter.FilterTest.Post, destination_field: :author1_id
|
||||
has_many :posts, Ash.Test.Filter.FilterTest.Post, destination_attribute: :author1_id
|
||||
|
||||
has_many :second_posts, Ash.Test.Filter.FilterTest.Post, destination_field: :author1_id
|
||||
has_many :second_posts, Ash.Test.Filter.FilterTest.Post, destination_attribute: :author1_id
|
||||
|
||||
has_one :profile, Profile, destination_field: :user_id
|
||||
has_one :profile, Profile, destination_attribute: :user_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -118,23 +118,23 @@ defmodule Ash.Test.Filter.FilterTest do
|
|||
|
||||
relationships do
|
||||
belongs_to :author1, User,
|
||||
destination_field: :id,
|
||||
source_field: :author1_id
|
||||
destination_attribute: :id,
|
||||
source_attribute: :author1_id
|
||||
|
||||
belongs_to :special_author1, User,
|
||||
destination_field: :id,
|
||||
source_field: :author1_id,
|
||||
define_field?: false,
|
||||
destination_attribute: :id,
|
||||
source_attribute: :author1_id,
|
||||
define_attribute?: false,
|
||||
filter: expr(special == true)
|
||||
|
||||
belongs_to :author2, User,
|
||||
destination_field: :id,
|
||||
source_field: :author2_id
|
||||
destination_attribute: :id,
|
||||
source_attribute: :author2_id
|
||||
|
||||
many_to_many :related_posts, __MODULE__,
|
||||
through: PostLink,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -25,10 +25,10 @@ defmodule Ash.Test.GeneratorTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.GeneratorTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.GeneratorTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_one :latest_post, Ash.Test.GeneratorTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
sort: [inserted_at: :desc]
|
||||
end
|
||||
end
|
||||
|
@ -60,8 +60,8 @@ defmodule Ash.Test.GeneratorTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.GeneratorTest.Category,
|
||||
through: Ash.Test.GeneratorTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,8 +110,8 @@ defmodule Ash.Test.GeneratorTest do
|
|||
relationships do
|
||||
many_to_many :posts, Post,
|
||||
through: PostCategory,
|
||||
destination_field_on_join_table: :post_id,
|
||||
source_field_on_join_table: :category_id
|
||||
destination_attribute_on_join_resource: :post_id,
|
||||
source_attribute_on_join_resource: :category_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -87,10 +87,10 @@ defmodule Ash.Test.NotifierTest do
|
|||
relationships do
|
||||
many_to_many :related_posts, __MODULE__,
|
||||
through: PostLink,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
|
||||
has_many :comments, Comment, destination_field: :post_id
|
||||
has_many :comments, Comment, destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ defmodule Ash.Test.Resource.AggregatesTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :comments, Comment, destination_field: :post_id
|
||||
has_many :comments, Comment, destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -85,7 +85,7 @@ defmodule Ash.Test.Resource.AggregatesTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :comments, Comment, destination_field: :post_id
|
||||
has_many :comments, Comment, destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@ defmodule Ash.Test.Resource.InfoTest do
|
|||
relationships do
|
||||
many_to_many :tags, Tag do
|
||||
through TagOnPost
|
||||
source_field_on_join_table :vendor_id
|
||||
destination_field_on_join_table :shipping_method_id
|
||||
source_attribute_on_join_resource(:vendor_id)
|
||||
destination_attribute_on_join_resource(:shipping_method_id)
|
||||
end
|
||||
|
||||
has_many :comments, Comment, destination_field: :post_id
|
||||
has_one :private, PostPrivate, destination_field: :post_id
|
||||
has_many :comments, Comment, destination_attribute: :post_id
|
||||
has_one :private, PostPrivate, destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -78,32 +78,32 @@ defmodule Ash.Test.Resource.Relationships.BelongsToTest do
|
|||
defposts do
|
||||
relationships do
|
||||
belongs_to(:foo, Foo)
|
||||
belongs_to(:bar, Bar, source_field: :bazz, private?: true)
|
||||
belongs_to(:bar, Bar, source_attribute: :bazz, private?: true)
|
||||
end
|
||||
end
|
||||
|
||||
assert [
|
||||
%BelongsTo{
|
||||
cardinality: :one,
|
||||
define_field?: true,
|
||||
define_attribute?: true,
|
||||
destination: Foo,
|
||||
destination_field: :id,
|
||||
field_type: :uuid,
|
||||
destination_attribute: :id,
|
||||
attribute_type: :uuid,
|
||||
name: :foo,
|
||||
primary_key?: false,
|
||||
source_field: :foo_id,
|
||||
source_attribute: :foo_id,
|
||||
type: :belongs_to,
|
||||
private?: false
|
||||
},
|
||||
%BelongsTo{
|
||||
cardinality: :one,
|
||||
define_field?: true,
|
||||
define_attribute?: true,
|
||||
destination: Bar,
|
||||
destination_field: :id,
|
||||
field_type: :uuid,
|
||||
destination_attribute: :id,
|
||||
attribute_type: :uuid,
|
||||
name: :bar,
|
||||
primary_key?: false,
|
||||
source_field: :bazz,
|
||||
source_attribute: :bazz,
|
||||
type: :belongs_to,
|
||||
private?: true
|
||||
}
|
||||
|
@ -120,28 +120,28 @@ defmodule Ash.Test.Resource.Relationships.BelongsToTest do
|
|||
end
|
||||
|
||||
describe "validations" do
|
||||
test "fails if destination_field is not an atom" do
|
||||
test "fails if destination_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :destination_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :destination_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
belongs_to(:foobar, FooBar, destination_field: "foo")
|
||||
belongs_to(:foobar, FooBar, destination_attribute: "foo")
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "fails if source_field is not an atom" do
|
||||
test "fails if source_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :source_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :source_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
belongs_to(:foobar, FooBar, source_field: "foo")
|
||||
belongs_to(:foobar, FooBar, source_attribute: "foo")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -205,14 +205,14 @@ defmodule Ash.Test.Resource.Relationships.BelongsToTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "fails if `define_field?` is not a boolean" do
|
||||
test "fails if `define_attribute?` is not a boolean" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :define_field? to be a boolean, got: \"blah\"",
|
||||
"[Ash.Test.Resource.Relationships.BelongsToTest.Post]\n relationships -> belongs_to -> foobar:\n expected :define_attribute? to be a boolean, got: \"blah\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
belongs_to(:foobar, Foobar, define_field?: "blah")
|
||||
belongs_to(:foobar, Foobar, define_attribute?: "blah")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -226,7 +226,7 @@ defmodule Ash.Test.Resource.Relationships.BelongsToTest do
|
|||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
belongs_to(:post, __MODULE__, define_field?: false)
|
||||
belongs_to(:post, __MODULE__, define_attribute?: false)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ defmodule Ash.Test.Resource.Relationships.HasManyTest do
|
|||
defposts do
|
||||
relationships do
|
||||
has_many :foo, Foo
|
||||
has_many :bar, Bar, destination_field: :bazz, private?: true
|
||||
has_many :bar, Bar, destination_attribute: :bazz, private?: true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -32,18 +32,18 @@ defmodule Ash.Test.Resource.Relationships.HasManyTest do
|
|||
%HasMany{
|
||||
cardinality: :many,
|
||||
destination: Foo,
|
||||
destination_field: :post_id,
|
||||
destination_attribute: :post_id,
|
||||
name: :foo,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_many,
|
||||
private?: false
|
||||
},
|
||||
%HasMany{
|
||||
cardinality: :many,
|
||||
destination: Bar,
|
||||
destination_field: :bazz,
|
||||
destination_attribute: :bazz,
|
||||
name: :bar,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_many,
|
||||
private?: true
|
||||
}
|
||||
|
@ -60,28 +60,28 @@ defmodule Ash.Test.Resource.Relationships.HasManyTest do
|
|||
end
|
||||
|
||||
describe "validations" do
|
||||
test "fails if destination_field is not an atom" do
|
||||
test "fails if destination_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.HasManyTest.Post]\n relationships -> has_many -> foobar:\n expected :destination_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.HasManyTest.Post]\n relationships -> has_many -> foobar:\n expected :destination_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_many :foobar, FooBar, destination_field: "foo"
|
||||
has_many :foobar, FooBar, destination_attribute: "foo"
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "fails if source_field is not an atom" do
|
||||
test "fails if source_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.HasManyTest.Post]\n relationships -> has_many -> foobar:\n expected :source_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.HasManyTest.Post]\n relationships -> has_many -> foobar:\n expected :source_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_many :foobar, FooBar, source_field: "foo", destination_field: :post_id
|
||||
has_many :foobar, FooBar, source_attribute: "foo", destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -123,7 +123,7 @@ defmodule Ash.Test.Resource.Relationships.HasManyTest do
|
|||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_many :foobar, FooBar, private?: "foo", destination_field: :post_id
|
||||
has_many :foobar, FooBar, private?: "foo", destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,8 +23,8 @@ defmodule Ash.Test.Resource.Relationships.HasOneTest do
|
|||
test "it creates a relationship" do
|
||||
defposts do
|
||||
relationships do
|
||||
has_one :foo, Foo, destination_field: :post_id
|
||||
has_one :bar, Bar, destination_field: :post_id, private?: true
|
||||
has_one :foo, Foo, destination_attribute: :post_id
|
||||
has_one :bar, Bar, destination_attribute: :post_id, private?: true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -32,18 +32,18 @@ defmodule Ash.Test.Resource.Relationships.HasOneTest do
|
|||
%HasOne{
|
||||
cardinality: :one,
|
||||
destination: Foo,
|
||||
destination_field: :post_id,
|
||||
destination_attribute: :post_id,
|
||||
name: :foo,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_one,
|
||||
private?: false
|
||||
},
|
||||
%HasOne{
|
||||
cardinality: :one,
|
||||
destination: Bar,
|
||||
destination_field: :post_id,
|
||||
destination_attribute: :post_id,
|
||||
name: :bar,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_one,
|
||||
private?: true
|
||||
}
|
||||
|
@ -60,28 +60,28 @@ defmodule Ash.Test.Resource.Relationships.HasOneTest do
|
|||
end
|
||||
|
||||
describe "validations" do
|
||||
test "fails if destination_field is not an atom" do
|
||||
test "fails if destination_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.HasOneTest.Post]\n relationships -> has_one -> foobar:\n expected :destination_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.HasOneTest.Post]\n relationships -> has_one -> foobar:\n expected :destination_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_one :foobar, FooBar, destination_field: "foo"
|
||||
has_one :foobar, FooBar, destination_attribute: "foo"
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "fails if source_field is not an atom" do
|
||||
test "fails if source_attribute is not an atom" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.HasOneTest.Post]\n relationships -> has_one -> foobar:\n expected :source_field to be an atom, got: \"foo\"",
|
||||
"[Ash.Test.Resource.Relationships.HasOneTest.Post]\n relationships -> has_one -> foobar:\n expected :source_attribute to be an atom, got: \"foo\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_one :foobar, FooBar, source_field: "foo", destination_field: :post_id
|
||||
has_one :foobar, FooBar, source_attribute: "foo", destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -123,7 +123,7 @@ defmodule Ash.Test.Resource.Relationships.HasOneTest do
|
|||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
has_one :foobar, FooBar, private?: "foo", destination_field: :post_id
|
||||
has_one :foobar, FooBar, private?: "foo", destination_attribute: :post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -27,13 +27,13 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
relationships do
|
||||
many_to_many :related_posts, Post,
|
||||
through: SomeResource,
|
||||
source_field_on_join_table: :post_id,
|
||||
destination_field_on_join_table: :related_post_id
|
||||
source_attribute_on_join_resource: :post_id,
|
||||
destination_attribute_on_join_resource: :related_post_id
|
||||
|
||||
many_to_many :unrelated_posts, Post,
|
||||
through: Tabloid,
|
||||
source_field_on_join_table: :post_id,
|
||||
destination_field_on_join_table: :unrelated_post_id,
|
||||
source_attribute_on_join_resource: :post_id,
|
||||
destination_attribute_on_join_resource: :unrelated_post_id,
|
||||
private?: true
|
||||
end
|
||||
end
|
||||
|
@ -42,32 +42,32 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
%HasMany{
|
||||
cardinality: :many,
|
||||
destination: Tabloid,
|
||||
destination_field: :post_id,
|
||||
destination_attribute: :post_id,
|
||||
name: :unrelated_posts_join_assoc,
|
||||
source: ManyToManyTest.Post,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_many,
|
||||
private?: true
|
||||
},
|
||||
%HasMany{
|
||||
cardinality: :many,
|
||||
destination: SomeResource,
|
||||
destination_field: :post_id,
|
||||
destination_attribute: :post_id,
|
||||
name: :related_posts_join_assoc,
|
||||
source: ManyToManyTest.Post,
|
||||
source_field: :id,
|
||||
source_attribute: :id,
|
||||
type: :has_many,
|
||||
private?: true
|
||||
},
|
||||
%ManyToMany{
|
||||
cardinality: :many,
|
||||
destination: ManyToManyTest.Post,
|
||||
destination_field: :id,
|
||||
destination_field_on_join_table: :related_post_id,
|
||||
destination_attribute: :id,
|
||||
destination_attribute_on_join_resource: :related_post_id,
|
||||
name: :related_posts,
|
||||
source: ManyToManyTest.Post,
|
||||
source_field: :id,
|
||||
source_field_on_join_table: :post_id,
|
||||
source_attribute: :id,
|
||||
source_attribute_on_join_resource: :post_id,
|
||||
through: SomeResource,
|
||||
type: :many_to_many,
|
||||
private?: false
|
||||
|
@ -75,12 +75,12 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
%ManyToMany{
|
||||
cardinality: :many,
|
||||
destination: ManyToManyTest.Post,
|
||||
destination_field: :id,
|
||||
destination_field_on_join_table: :unrelated_post_id,
|
||||
destination_attribute: :id,
|
||||
destination_attribute_on_join_resource: :unrelated_post_id,
|
||||
name: :unrelated_posts,
|
||||
source: ManyToManyTest.Post,
|
||||
source_field: :id,
|
||||
source_field_on_join_table: :post_id,
|
||||
source_attribute: :id,
|
||||
source_attribute_on_join_resource: :post_id,
|
||||
through: Tabloid,
|
||||
type: :many_to_many,
|
||||
private?: true
|
||||
|
@ -108,8 +108,8 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: "some_table",
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -121,76 +121,76 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBars,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "it fails if you dont pass an atom for `source_field_on_join_table`" do
|
||||
test "it fails if you dont pass an atom for `source_attribute_on_join_resource`" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :source_field_on_join_table to be an atom, got: \"what\"",
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :source_attribute_on_join_resource to be an atom, got: \"what\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBars,
|
||||
source_field_on_join_table: "what",
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute_on_join_resource: "what",
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "it fails if you dont pass an atom for `destination_field_on_join_table`" do
|
||||
test "it fails if you dont pass an atom for `destination_attribute_on_join_resource`" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :destination_field_on_join_table to be an atom, got: \"what\"",
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :destination_attribute_on_join_resource to be an atom, got: \"what\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBar,
|
||||
destination_field_on_join_table: "what",
|
||||
source_field_on_join_table: :source_post_id
|
||||
destination_attribute_on_join_resource: "what",
|
||||
source_attribute_on_join_resource: :source_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "it fails if you dont pass an atom for `source_field`" do
|
||||
test "it fails if you dont pass an atom for `source_attribute`" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :source_field to be an atom, got: \"what\"",
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :source_attribute to be an atom, got: \"what\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBar,
|
||||
source_field: "what",
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
source_attribute: "what",
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
test "it fails if you dont pass an atom for `destination_field`" do
|
||||
test "it fails if you dont pass an atom for `destination_attribute`" do
|
||||
assert_raise(
|
||||
Spark.Error.DslError,
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :destination_field to be an atom, got: \"what\"",
|
||||
"[Ash.Test.Resource.Relationships.ManyToManyTest.Post]\n relationships -> many_to_many -> foobars:\n expected :destination_attribute to be an atom, got: \"what\"",
|
||||
fn ->
|
||||
defposts do
|
||||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBars,
|
||||
destination_field: "what",
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id
|
||||
destination_attribute: "what",
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -206,8 +206,8 @@ defmodule Ash.Test.Resource.Relationships.ManyToManyTest do
|
|||
relationships do
|
||||
many_to_many :foobars, Foobar,
|
||||
through: FooBars,
|
||||
source_field_on_join_table: :source_post_id,
|
||||
destination_field_on_join_table: :destination_post_id,
|
||||
source_attribute_on_join_resource: :source_post_id,
|
||||
destination_attribute_on_join_resource: :destination_post_id,
|
||||
private?: "an_invalid_field"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -24,10 +24,10 @@ defmodule Ash.Test.SeedTest do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many :posts, Ash.Test.SeedTest.Post, destination_field: :author_id
|
||||
has_many :posts, Ash.Test.SeedTest.Post, destination_attribute: :author_id
|
||||
|
||||
has_one :latest_post, Ash.Test.SeedTest.Post,
|
||||
destination_field: :author_id,
|
||||
destination_attribute: :author_id,
|
||||
sort: [inserted_at: :desc]
|
||||
end
|
||||
end
|
||||
|
@ -61,8 +61,8 @@ defmodule Ash.Test.SeedTest do
|
|||
|
||||
many_to_many :categories, Ash.Test.SeedTest.Category,
|
||||
through: Ash.Test.SeedTest.PostCategory,
|
||||
destination_field_on_join_table: :category_id,
|
||||
source_field_on_join_table: :post_id
|
||||
destination_attribute_on_join_resource: :category_id,
|
||||
source_attribute_on_join_resource: :post_id
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -107,8 +107,8 @@ defmodule Ash.Test.SeedTest do
|
|||
relationships do
|
||||
many_to_many :posts, Post,
|
||||
through: PostCategory,
|
||||
destination_field_on_join_table: :post_id,
|
||||
source_field_on_join_table: :category_id
|
||||
destination_attribute_on_join_resource: :post_id,
|
||||
source_attribute_on_join_resource: :category_id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ defmodule Ash.Test.Support.PolicyRbac.Organization do
|
|||
|
||||
relationships do
|
||||
has_many :memberships, Ash.Test.Support.PolicyRbac.Membership do
|
||||
destination_field(:organization_id)
|
||||
destination_attribute(:organization_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ defmodule Ash.Test.Support.PolicyRbac.User do
|
|||
end
|
||||
|
||||
relationships do
|
||||
has_many(:memberships, Ash.Test.Support.PolicyRbac.Membership, destination_field: :user_id)
|
||||
has_many(:memberships, Ash.Test.Support.PolicyRbac.Membership, destination_attribute: :user_id)
|
||||
|
||||
belongs_to(:organization, Ash.Test.Support.PolicyRbac.Organization)
|
||||
end
|
||||
|
|
|
@ -31,8 +31,8 @@ defmodule Ash.Test.Support.PolicySimple.Car do
|
|||
relationships do
|
||||
many_to_many :users, Ash.Test.Support.PolicySimple.User do
|
||||
through(Ash.Test.Support.PolicySimple.CarUser)
|
||||
source_field_on_join_table(:car_id)
|
||||
destination_field_on_join_table(:user_id)
|
||||
source_attribute_on_join_resource(:car_id)
|
||||
destination_attribute_on_join_resource(:user_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,12 +32,12 @@ defmodule Ash.Test.Support.PolicySimple.User do
|
|||
|
||||
relationships do
|
||||
belongs_to(:organization, Ash.Test.Support.PolicySimple.Organization)
|
||||
has_many(:posts, Ash.Test.Support.PolicySimple.Post, destination_field: :author_id)
|
||||
has_many(:posts, Ash.Test.Support.PolicySimple.Post, destination_attribute: :author_id)
|
||||
|
||||
many_to_many :cars, Ash.Test.Support.PolicySimple.Car do
|
||||
through(Ash.Test.Support.PolicySimple.CarUser)
|
||||
source_field_on_join_table(:user_id)
|
||||
destination_field_on_join_table(:car_id)
|
||||
source_attribute_on_join_resource(:user_id)
|
||||
destination_attribute_on_join_resource(:car_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue