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

- old
+ new

@@ -1,30 +1,28 @@ require "spec_helper" require "support/have_persisted_matcher" -require "support/mapper_setup" -require "support/sequel_persistence_setup" +require "support/object_store_setup" require "support/seed_data_setup" require "terrestrial" RSpec.describe "Graph persistence" do - include_context "mapper setup" - include_context "sequel persistence setup" + include_context "object store setup" include_context "seed data setup" - subject(:mapper) { mappers.fetch(:users) } + subject(:user_store) { object_store.fetch(:users) } let(:user) { - mapper.where(id: "users/1").first + user_store.where(id: "users/1").first } context "without associations" do - let(:modified_email) { "bestie+modified@gmail.com" } + let(:modified_email) { "hasel+modified@gmail.com" } it "saves the root object" do user.email = modified_email - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :users, hash_including( id: "users/1", @@ -33,11 +31,11 @@ ) end it "doesn't send associated objects to the database as columns" do user.email = modified_email - mapper.save(user) + user_store.save(user) expect(datastore).not_to have_persisted( :users, hash_including( posts: anything, @@ -48,11 +46,11 @@ # TODO move to a dirty tracking spec? context "when mutating entity fields in place" do it "saves the object" do user.email << "MUTATED" - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :users, hash_including( id: "users/1", @@ -67,11 +65,11 @@ let(:post) { user.posts.first } let(:modified_post_body) { "modified ur body" } it "saves the associated object" do post.body = modified_post_body - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :posts, hash_including( id: post.id, @@ -90,11 +88,11 @@ let(:modified_comment_body) { "body moving, body moving" } it "saves the associated object" do comment.body = modified_comment_body - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :comments, hash_including( { @@ -131,21 +129,33 @@ end it "persists the object" do user.posts.push(new_post) - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :posts, hash_including( id: "posts/neu", author_id: user.id, subject: "I am new", ) ) end + + context "when the collection is not loaded until the new object is persisted" do + it "is consistent with the datastore" do + user.posts.push(new_post) + + user_store.save(user) + + expect(user.posts.to_a.map(&:id)).to eq( + ["posts/1", "posts/2", "posts/neu"] + ) + end + end end context "delete an object from a has many association" do let(:post) { user.posts.first } @@ -155,11 +165,11 @@ expect(user.posts.map(&:id)).not_to include(post.id) end it "delete the object from the datastore on save" do user.posts.delete(post) - mapper.save(user) + user_store.save(user) expect(datastore).not_to have_persisted( :posts, hash_including( id: post.id, @@ -180,11 +190,11 @@ end it "deletes the 'join table' record" do category = post.categories.first post.categories.delete(category) - mapper.save(user) + user_store.save(user) expect(datastore).not_to have_persisted( :categories_to_posts, { post_id: post.id, @@ -194,11 +204,11 @@ end it "does not delete the object" do category = post.categories.first post.categories.delete(category) - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :categories, hash_including( id: category.id, @@ -218,11 +228,11 @@ .to match_array(["categories/1", "categories/2"]) end it "persists the change" do post_with_one_category.categories.push(new_category) - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :categories_to_posts, { post_id: post_with_one_category.id, @@ -243,11 +253,11 @@ .to eq(modified_category_name) end it "persists the change" do category.name = modified_category_name - mapper.save(user) + user_store.save(user) expect(datastore).to have_persisted( :categories, { id: category.id, @@ -256,17 +266,17 @@ ) end end context "node loaded as root has undefined one to many association" do - let(:post_mapper) { mappers[:posts] } - let(:post) { post_mapper.where(id: "posts/1").first } + let(:post_store) { object_store[:posts] } + let(:post) { post_store.where(id: "posts/1").first } it "persists the changes to the root node" do post.body = "modified body" - post_mapper.save(post) + post_store.save(post) expect(datastore).to have_persisted( :posts, hash_including( id: "posts/1", @@ -276,11 +286,11 @@ end it "does not overwrite unused foreign key" do post.body = "modified body" - post_mapper.save(post) + post_store.save(post) expect(datastore).to have_persisted( :posts, hash_including( id: "posts/1", @@ -289,21 +299,67 @@ ) end end end + 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", + subject: "Nils gonna getcha", + body: "", + created_at: Time.parse("2015-09-05T15:00:00+01:00"), + categories: [], + comments: [], + ) + + object_store[:posts].save(post) + + expect(datastore).to have_persisted( + :posts, + hash_including( + id: "posts/orphan", + author_id: nil, + ) + ) + end + end + + context "when an existing partent object reference is set to nil" do + it "populates that association with a nil" do + comment = user + .posts + .flat_map(&:comments) + .detect { |c| c.id == "comments/1" } + + comment.commenter = nil + + user_store.save(user) + + expect(datastore).to have_persisted( + :comments, + hash_including( + id: "comments/1", + commenter_id: nil, + ) + ) + end + end + end + context "when a save operation fails (some object is not persistable)" do let(:unpersistable_object) { ->() { } } it "rolls back the transaction" do pre_change = datastore[:users].to_a.map(&:to_a).sort begin user.first_name = "this will be rolled back" user.posts.first.subject = unpersistable_object - mapper.save(user) - rescue Sequel::Error + user_store.save(user) + rescue Terrestrial::Error end post_change = datastore[:users].to_a.map(&:to_a).sort expect(pre_change).to eq(post_change)