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