Skip to content

Commit

Permalink
Match has_one direction before deleting rel
Browse files Browse the repository at this point in the history
When relationship_corresponding_rel matches on the rel class name,
it stops on the first match, ignoring the direction parameter.

When target_class represents the to_node, direction is :in.

When the relationship is a has_one/has_many between a pair
of nodes of the same class, the match could find and return
the to_node's :out association first, causing
delete_reverse_has_one_relationship() to delete it.

Checking the direction first prevents that.
  • Loading branch information
bobmazanec committed Aug 29, 2021
1 parent 95f249d commit 7a6cb2d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 2 deletions.
6 changes: 4 additions & 2 deletions lib/active_graph/node/has_n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -253,8 +253,10 @@ def delete_has_one_rel!(rel)

def relationship_corresponding_rel(relationship, direction, target_class)
self.class.associations.find do |_key, assoc|
assoc.relationship_class_name == relationship.class.name ||
(assoc.relationship_type == relationship.type.to_sym && assoc.target_class == target_class && assoc.direction == direction)
assoc.direction == direction && (
assoc.relationship_class_name == relationship.class.name ||
(assoc.relationship_type == relationship.type.to_sym && assoc.target_class == target_class)
)
end
end

Expand Down
61 changes: 61 additions & 0 deletions spec/e2e/relationship_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -589,4 +589,65 @@ class ActiveRelSpecTypesInheritedRelClass < ActiveRelSpecTypesAutomaticRelType
end
end
end

context "between nodes of the same class" do
before(:each) do
clear_model_memory_caches

stub_node_class('NodeClass') do
has_one :out, :parent, rel_class: :IsParentOf
has_many :in, :children, rel_class: :IsParentOf
end

stub_relationship_class('IsParentOf') do
from_class :NodeClass
to_class :NodeClass
end

@gen0 = NodeClass.create
@gen1 = @gen2 = nil
end

after(:each) { [@gen0, @gen1, @gen2].compact.each(&:destroy) }

shared_examples_for :creating_gen2 do
it "creates (gen1)-->(gen0)" do
@gen1 = NodeClass.create parent: @gen0

expect(@gen1.parent.id).to eq @gen0.id

expect(@gen0.children.count).to eq 1
expect(@gen0.children.first.id).to eq @gen1.id
end

context "given (gen1)-->(gen0)" do
before(:each) { @gen1 = NodeClass.create parent: @gen0 }

describe "#create (gen2)-->(gen1)" do
it "adds a new node and relationsihp without affecting (gen1)-->(gen0)" do
@gen2 = NodeClass.create parent: @gen1

expect(@gen2.parent.id).to eq @gen1.id

expect(@gen1.children.count).to eq 1
expect(@gen1.children.first.id).to eq @gen2.id

expect(@gen1.parent).to(be_present, "gen1 lost its parent")
expect(@gen1.parent.id).to eq @gen0.id

expect(@gen0.children.count).to eq 1
expect(@gen0.children.first.id).to eq @gen1.id
end
end
end
end

%i(all none).each do |uniqueness|
context "with creates_unique(:#{uniqueness})" do
before(:each) { IsParentOf.creates_unique uniqueness }

include_examples :creating_gen2
end
end
end
end

0 comments on commit 7a6cb2d

Please sign in to comment.