From 40904cae806ed631bafd8c807295753422ac888f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 6 Jul 2022 08:29:46 -0400 Subject: [PATCH] fix: add back in `writable?` option to relationships, and add `attribute_writable?` to `belongs_to` --- .formatter.exs | 1 + lib/ash/changeset/changeset.ex | 9 +++++++++ lib/ash/resource/relationships/belongs_to.ex | 18 ++++++++++++------ lib/ash/resource/relationships/has_many.ex | 2 ++ lib/ash/resource/relationships/has_one.ex | 2 ++ lib/ash/resource/relationships/many_to_many.ex | 2 ++ .../resource/relationships/shared_options.ex | 7 +++++++ .../transformers/belongs_to_attribute.ex | 2 +- .../resource/relationships/belongs_to_test.exs | 18 ++++++++++++++++++ 9 files changed, 54 insertions(+), 7 deletions(-) diff --git a/.formatter.exs b/.formatter.exs index 20640363..fc57a60c 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -18,6 +18,7 @@ locals_without_parens = [ attribute: 1, attribute: 2, attribute: 3, + attribute_writable?: 1, authorize_if: 1, authorize_if: 2, authorize_unless: 1, diff --git a/lib/ash/changeset/changeset.ex b/lib/ash/changeset/changeset.ex index 86c827b8..957ddd99 100644 --- a/lib/ash/changeset/changeset.ex +++ b/lib/ash/changeset/changeset.ex @@ -1796,6 +1796,15 @@ defmodule Ash.Changeset do add_error(changeset, error) + %{writable?: false} = relationship -> + error = + InvalidRelationship.exception( + relationship: relationship.name, + message: "Relationship is not editable" + ) + + add_error(changeset, error) + %{manual: manual} = relationship when not is_nil(manual) -> error = InvalidRelationship.exception( diff --git a/lib/ash/resource/relationships/belongs_to.ex b/lib/ash/resource/relationships/belongs_to.ex index a3819690..70f3f69e 100644 --- a/lib/ash/resource/relationships/belongs_to.ex +++ b/lib/ash/resource/relationships/belongs_to.ex @@ -21,6 +21,7 @@ defmodule Ash.Resource.Relationships.BelongsTo do :writable?, :context, :description, + :attribute_writable?, validate_destination_field?: true, cardinality: :one, type: :belongs_to @@ -39,6 +40,8 @@ defmodule Ash.Resource.Relationships.BelongsTo do primary_key?: boolean, define_field?: boolean, field_type: term, + writable?: boolean, + attribute_writable?: boolean, destination_field: atom, private?: boolean, source_field: atom | nil, @@ -56,12 +59,6 @@ defmodule Ash.Resource.Relationships.BelongsTo do @opt_schema Ash.OptionsHelpers.merge_schemas( [ - writable?: [ - type: :boolean, - doc: - "Whether or not the attribute created by this relationship will be marked with `writable?: true`.", - default: false - ], primary_key?: [ type: :boolean, default: false, @@ -73,6 +70,15 @@ defmodule Ash.Resource.Relationships.BelongsTo do doc: "Whether this relationship must always be present, e.g: must be included on creation, and never removed (it can still be changed)" ], + attribute_writable?: [ + type: :boolean, + default: false, + doc: """ + Whether this relationship's generated attribute will be marked as writable. + + Has no effect when combined with `define_field?: false`. + """ + ], define_field?: [ type: :boolean, default: true, diff --git a/lib/ash/resource/relationships/has_many.ex b/lib/ash/resource/relationships/has_many.ex index 483bea17..3b215f3e 100644 --- a/lib/ash/resource/relationships/has_many.ex +++ b/lib/ash/resource/relationships/has_many.ex @@ -16,6 +16,7 @@ defmodule Ash.Resource.Relationships.HasMany do :violation_message, :manual, :api, + :writable?, no_fields?: false, could_be_related_at_creation?: false, validate_destination_field?: true, @@ -32,6 +33,7 @@ defmodule Ash.Resource.Relationships.HasMany do no_fields?: boolean, name: atom, type: Ash.Type.t(), + writable?: boolean, destination: Ash.Resource.t(), destination_field: atom, private?: boolean, diff --git a/lib/ash/resource/relationships/has_one.ex b/lib/ash/resource/relationships/has_one.ex index ec2b08e3..81de3387 100644 --- a/lib/ash/resource/relationships/has_one.ex +++ b/lib/ash/resource/relationships/has_one.ex @@ -18,6 +18,7 @@ defmodule Ash.Resource.Relationships.HasOne do :not_found_message, :violation_message, :manual, + :writable?, no_fields?: false, could_be_related_at_creation?: false, validate_destination_field?: true, @@ -33,6 +34,7 @@ defmodule Ash.Resource.Relationships.HasOne do name: atom, read_action: atom, no_fields?: boolean, + writable?: boolean, type: Ash.Type.t(), filter: Ash.Filter.t() | nil, destination: Ash.Resource.t(), diff --git a/lib/ash/resource/relationships/many_to_many.ex b/lib/ash/resource/relationships/many_to_many.ex index 80dd707a..621627c8 100644 --- a/lib/ash/resource/relationships/many_to_many.ex +++ b/lib/ash/resource/relationships/many_to_many.ex @@ -19,6 +19,7 @@ defmodule Ash.Resource.Relationships.ManyToMany do :description, :context, :filter, + :has_many, could_be_related_at_creation?: false, validate_destination_field?: true, cardinality: :many, @@ -29,6 +30,7 @@ defmodule Ash.Resource.Relationships.ManyToMany do type: :many_to_many, cardinality: :many, source: Ash.Resource.t(), + has_many: boolean, private?: boolean, filter: Ash.Filter.t() | nil, read_action: atom, diff --git a/lib/ash/resource/relationships/shared_options.ex b/lib/ash/resource/relationships/shared_options.ex index bb1e29c7..a3c28386 100644 --- a/lib/ash/resource/relationships/shared_options.ex +++ b/lib/ash/resource/relationships/shared_options.ex @@ -53,6 +53,13 @@ defmodule Ash.Resource.Relationships.SharedOptions do For example, if a value is added that has no match in the destination (very hard to do with the way Ash relationship changes work). """ ], + writable?: [ + type: :boolean, + default: true, + doc: """ + Wether or not the relationship may be edited. + """ + ], read_action: [ type: :atom, doc: """ diff --git a/lib/ash/resource/transformers/belongs_to_attribute.ex b/lib/ash/resource/transformers/belongs_to_attribute.ex index 9cd1afbc..f7cf45af 100644 --- a/lib/ash/resource/transformers/belongs_to_attribute.ex +++ b/lib/ash/resource/transformers/belongs_to_attribute.ex @@ -29,7 +29,7 @@ defmodule Ash.Resource.Transformers.BelongsToAttribute do else not relationship.required? end, - writable?: relationship.writable?, + writable?: relationship.attribute_writable?, private?: true, primary_key?: relationship.primary_key? ) diff --git a/test/resource/relationships/belongs_to_test.exs b/test/resource/relationships/belongs_to_test.exs index ee56d7d3..da016672 100644 --- a/test/resource/relationships/belongs_to_test.exs +++ b/test/resource/relationships/belongs_to_test.exs @@ -56,6 +56,24 @@ defmodule Ash.Test.Resource.Relationships.BelongsToTest do ] = Ash.Resource.Info.attributes(Post) end + test "it creates an attribute that honors attribute_writable?" do + defposts do + relationships do + belongs_to(:foobar, FooBar, attribute_writable?: true) + end + end + + assert [ + _, + %Ash.Resource.Attribute{ + name: :foobar_id, + primary_key?: false, + type: Ash.Type.UUID, + writable?: true + } + ] = Ash.Resource.Info.attributes(Post) + end + test "it creates a relationship" do defposts do relationships do