From cb6c99c000244fc0a07dbb54959b78536954ed77 Mon Sep 17 00:00:00 2001 From: Matt Gibson Date: Fri, 18 Jun 2021 15:54:51 +0100 Subject: [PATCH] Allow an adapter to return a new object to replace the existing one. This is to enable the use of an adapter that returns Dry::Structs, which are immutable. Associating parents or children needs to involve creation of a new object, rather than modifying the one passed in by reference as a parameter. --- lib/graphiti/adapters/abstract.rb | 4 ++++ lib/graphiti/adapters/active_record.rb | 5 +++++ lib/graphiti/util/persistence.rb | 27 +++++++++++++++----------- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/lib/graphiti/adapters/abstract.rb b/lib/graphiti/adapters/abstract.rb index 08ceda26..5d048cac 100644 --- a/lib/graphiti/adapters/abstract.rb +++ b/lib/graphiti/adapters/abstract.rb @@ -364,6 +364,8 @@ def associate_all(parent, children, association_name, association_type) associate(parent, c, association_name, association_type) end end + + parent end def associate(parent, child, association_name, association_type) @@ -379,6 +381,8 @@ def associate(parent, child, association_name, association_type) else parent.send(:"#{association_name}=", child) end + + parent end def disassociate(parent, child, association_name, association_type) diff --git a/lib/graphiti/adapters/active_record.rb b/lib/graphiti/adapters/active_record.rb index f96e8b50..becfe1c6 100644 --- a/lib/graphiti/adapters/active_record.rb +++ b/lib/graphiti/adapters/active_record.rb @@ -255,6 +255,8 @@ def associate_all(parent, children, association_name, association_type) else super end + + parent end def associate(parent, child, association_name, association_type) @@ -265,6 +267,8 @@ def associate(parent, child, association_name, association_type) else super end + + parent end # When a has_and_belongs_to_many relationship, we don't have a foreign @@ -275,6 +279,7 @@ def disassociate(parent, child, association_name, association_type) parent.send(association_name).delete(child) end # Nothing to do in the else case, happened when we merged foreign key + parent end # (see Adapters::Abstract#create) diff --git a/lib/graphiti/util/persistence.rb b/lib/graphiti/util/persistence.rb index 05e63723..a0c5a6ae 100644 --- a/lib/graphiti/util/persistence.rb +++ b/lib/graphiti/util/persistence.rb @@ -51,11 +51,11 @@ def run @resource.decorate_record(persisted) assign_temp_id(persisted, @meta[:temp_id]) - associate_parents(persisted, parents) + persisted = associate_parents(persisted, parents) children = @adapter.process_has_many(self, persisted) - associate_children(persisted, children) unless @meta[:method] == :destroy + persisted = associate_children(persisted, children) unless @meta[:method] == :destroy post_process(persisted, parents) post_process(persisted, children) @@ -93,38 +93,42 @@ def associate_parents(object, parents) if x[:object] && object if x[:meta][:method] == :disassociate if x[:sideload].type == :belongs_to - x[:sideload].disassociate(object, x[:object]) + object = x[:sideload].disassociate(object, x[:object]) else - x[:sideload].disassociate(x[:object], object) + object = x[:sideload].disassociate(x[:object], object) end elsif x[:sideload].type == :belongs_to - x[:sideload].associate(object, x[:object]) + object = x[:sideload].associate(object, x[:object]) elsif [:has_many, :many_to_many].include?(x[:sideload].type) - x[:sideload].associate_all(object, Array(x[:object])) + object = x[:sideload].associate_all(object, Array(x[:object])) else - x[:sideload].associate(x[:object], object) + object = x[:sideload].associate(x[:object], object) end end end + + object end def associate_children(object, children) children.each do |x| if x[:object] && object if x[:meta][:method] == :disassociate - x[:sideload].disassociate(object, x[:object]) + object = x[:sideload].disassociate(object, x[:object]) elsif x[:meta][:method] == :destroy if x[:sideload].type == :many_to_many - x[:sideload].disassociate(object, x[:object]) + object = x[:sideload].disassociate(object, x[:object]) end # otherwise, no need to disassociate destroyed objects elsif [:has_many, :many_to_many].include?(x[:sideload].type) - x[:sideload].associate_all(object, Array(x[:object])) + object = x[:sideload].associate_all(object, Array(x[:object])) else - x[:sideload].associate(object, x[:object]) + object = x[:sideload].associate(object, x[:object]) end end end + + object end def persist_object(method, attributes) @@ -151,6 +155,7 @@ def post_process(caller_model, processed) def assign_temp_id(object, temp_id) object.instance_variable_set(:@_jsonapi_temp_id, temp_id) + object end def metadata