spec/graph_persistence_spec.rb in terrestrial-0.3.0 vs spec/graph_persistence_spec.rb in terrestrial-0.5.0

- old
+ new

@@ -29,25 +29,12 @@ email: modified_email, ) ) end - it "doesn't send associated objects to the database as columns" do - user.email = modified_email - user_store.save(user) - - expect(datastore).not_to have_persisted( - :users, - hash_including( - posts: anything, - ) - ) - end - - # TODO move to a dirty tracking spec? - context "when mutating entity fields in place" do - it "saves the object" do + context "when mutating an entity's fields in place" do + it "updates the row with new, mutated values" do user.email << "MUTATED" user_store.save(user) expect(datastore).to have_persisted( @@ -108,15 +95,17 @@ context "add a node to a has many association" do let(:new_post_attrs) { { id: "posts/neu", + author: nil, subject: "I am new", body: "new body", comments: [], categories: [], created_at: Time.now, + updated_at: Time.now, } } let(:new_post) { Post.new(new_post_attrs) @@ -240,10 +229,51 @@ } ) end end + context "duplicate a node" do + let(:post_with_one_category) { user.posts.to_a.last } + + # Spoiler alert: it does mutate the graph + # + # Feature?: The posts <=> category relationship because unique when persisted + # because there are no indexes on the `categories_to_posts` table making + # the combination of foreign keys a de facto primary key. + # + # If there was an additional primary key id field without a unique index + # this would not be the case. + # + # It would be nice if the collection proxy for posts <=> categories was a + # variant that behaved like set. Unfortunately uniqueness can only be + # determined by the user-defind objects' identities as the proxy would + # not have access to datastore ids. + # + # Mappings are available when the proxy is constructed so this is + # possible but awkward. + xit "does not mutate the graph" do + existing_category = post_with_one_category.categories.first + post_with_one_category.categories.push(existing_category) + + expect(post_with_one_category.categories.map(&:id)) + .to eq(["categories/2"]) + end + + it "does not persist the change" do + existing_category = post_with_one_category.categories.first + post_with_one_category.categories.push(existing_category) + + user_store.save(user) + + expect( + datastore[:categories_to_posts] + .where(:post_id => post_with_one_category.id) + .count + ).to eq(1) + end + end + context "modify a node" do let(:category) { user.posts.first.categories.first } let(:modified_category_name) { "modified category" } it "mutates the graph" do @@ -304,13 +334,15 @@ context "when a many to one association is nil" do context "when the object does not have a reference to its parent" do it "populates that association with a nil" do post = Post.new( id: "posts/orphan", + author: nil, subject: "Nils gonna getcha", body: "", created_at: Time.parse("2015-09-05T15:00:00+01:00"), + updated_at: Time.parse("2015-09-05T15:00:00+01:00"), categories: [], comments: [], ) object_store[:posts].save(post) @@ -324,11 +356,11 @@ ) end end context "when an existing partent object reference is set to nil" do - it "populates that association with a nil" do + it "does not orphan the object and sets the foreign key according to position in the object graph" do comment = user .posts .flat_map(&:comments) .detect { |c| c.id == "comments/1" } @@ -338,11 +370,11 @@ expect(datastore).to have_persisted( :comments, hash_including( id: "comments/1", - commenter_id: nil, + commenter_id: "users/1", ) ) end end end @@ -356,11 +388,13 @@ begin user.first_name = "this will be rolled back" user.posts.first.subject = unpersistable_object user_store.save(user) - rescue Terrestrial::Error + rescue Object => e end + + expect(e).to be_a(Terrestrial::Error) post_change = datastore[:users].to_a.map(&:to_a).sort expect(pre_change).to eq(post_change) end