diff --git a/server/lib/monarch/model/changeset.rb b/server/lib/monarch/model/changeset.rb index 9d3da0d..24e4462 100644 --- a/server/lib/monarch/model/changeset.rb +++ b/server/lib/monarch/model/changeset.rb @@ -7,7 +7,7 @@ def initialize(record, dirty_fields) @record, @dirty_fields = record, dirty_fields @old_state = OldRecordState.new(record) dirty_fields.each do |field| - old_state[field] = field.remote_value + old_state.preserve_current_remote_value(field) end end @@ -19,6 +19,18 @@ def wire_representation wire_representation end + def inspect + inspect_hash = {} + dirty_fields.each do |field| + inspect_hash[field.name] = { + :old => old_state.field(field.name).value, + :new => field.value + } + end + inspect_hash.inspect + end + + protected class OldRecordState @@ -29,8 +41,8 @@ def initialize(record) @old_field_values_by_column_name = {} end - def []=(field, old_value) - old_field_values_by_column_name[field.name] = old_value + def preserve_current_remote_value(field) + old_field_values_by_column_name[field.name] = field.remote_value end def field(column_or_name) diff --git a/server/lib/monarch/model/relations/inner_join.rb b/server/lib/monarch/model/relations/inner_join.rb index 7563d3e..7b08808 100644 --- a/server/lib/monarch/model/relations/inner_join.rb +++ b/server/lib/monarch/model/relations/inner_join.rb @@ -73,7 +73,7 @@ def subscribe_to_operands end inserted_tuples = new_tuples - previous_tuples - updated_tuples = previous_tuples | new_tuples + updated_tuples = previous_tuples & new_tuples removed_tuples = previous_tuples - new_tuples inserted_tuples.each {|tuple| on_insert_node.publish(tuple)} @@ -81,17 +81,23 @@ def subscribe_to_operands removed_tuples.each {|tuple| on_remove_node.publish(tuple)} end) -# operand_subscriptions.add(right_operand.on_update do |right_tuple, changeset| -# predicate.find_matching_tuples(changeset.new_state, left_operand).each do |left_tuple| -# composite_tuple = tuple_class.new([left_tuple, right_tuple]) -# on_insert_node.publish(composite_tuple) -# end -# -# predicate.find_matching_tuples(changeset.old_state, left_operand).each do |left_tuple| -# composite_tuple = tuple_class.new([left_tuple, right_tuple]) -# on_remove_node.publish(composite_tuple) -# end -# end) + operand_subscriptions.add(right_operand.on_update do |right_tuple, changeset| + new_tuples = predicate.find_matching_tuples(changeset.new_state, left_operand).map do |left_tuple| + tuple_class.new([left_tuple, right_tuple]) + end + + previous_tuples = predicate.find_matching_tuples(changeset.old_state, left_operand).map do |left_tuple| + tuple_class.new([left_tuple, right_tuple]) + end + + inserted_tuples = new_tuples - previous_tuples + updated_tuples = previous_tuples & new_tuples + removed_tuples = previous_tuples - new_tuples + + inserted_tuples.each {|tuple| on_insert_node.publish(tuple)} + updated_tuples.each {|tuple| on_update_node.publish(tuple, changeset)} + removed_tuples.each {|tuple| on_remove_node.publish(tuple)} + end) operand_subscriptions.add(left_operand.on_remove do |left_tuple| predicate.find_matching_tuples(left_tuple, right_operand).each do |right_tuple| diff --git a/server/spec/monarch/model/relations/inner_join_spec.rb b/server/spec/monarch/model/relations/inner_join_spec.rb index 8715630..4286857 100644 --- a/server/spec/monarch/model/relations/inner_join_spec.rb +++ b/server/spec/monarch/model/relations/inner_join_spec.rb @@ -180,6 +180,23 @@ module Relations end end + describe "when the update causes some composite tuples that are already present to still be present in the join" do + it "fires #on_update events with those composite tuples and the changeset" do + blog = Blog.find("grain") + grain_posts = blog.blog_posts + blog.title = "Did you mean Barbie?" + blog.save + + on_insert_calls.should be_empty + + on_update_calls.length.should == grain_posts.size + on_update_calls.all? {|call| call[0][Blog] == blog && call[1].wire_representation == {"title" => "Did you mean Barbie?"}}.should be_true + Set.new(on_update_calls.map {|call| call[0][BlogPost]}).should == Set.new(grain_posts.all) + + on_remove_calls.should be_empty + end + end + describe "when the update causes some composite tuples to stop being present in the join and others to become present" do it "fires both #on_remove and #on_insert events" do post_1 = BlogPost.create(:blog_id => "fun") @@ -201,80 +218,86 @@ module Relations Set.new(on_remove_calls.map {|composite_tuple| composite_tuple[BlogPost]}).should == Set.new(grain_posts.all) end end + end + + describe "when a record in right operand is updated" do + describe "when the update causes some composite tuples to become present in the join" do + it "fires #on_insert events with all composite tuples that are now present in the join" do + post = BlogPost.create(:blog_id => "fun") + blog = Blog.unsafe_create(:id => "misery") + + + on_update_calls.should be_empty + + post.blog_id = "misery" + post.save + + on_insert_calls.length.should == 1 + + on_insert_calls.first[Blog].should == blog + on_insert_calls.first[BlogPost].should == post + + on_update_calls.should be_empty + on_remove_calls.should be_empty + end + end + + describe "when the update causes some composite tuples to stop being present in the join" do + it "fires #on_remove events with all composite tuples that were removed from the join" do + blog = Blog.find("grain") + post = blog.blog_posts.first + post.blog_id = "crapola" + post.save + + on_insert_calls.should be_empty + on_update_calls.should be_empty + on_remove_calls.length.should == 1 + + on_remove_calls.first[Blog].should == blog + on_remove_calls.first[BlogPost].should == post + end + end +# describe "when the update causes some composite tuples that are already present to still be present in the join" do it "fires #on_update events with those composite tuples and the changeset" do blog = Blog.find("grain") - grain_posts = blog.blog_posts - blog.title = "Did you mean Barbie?" - blog.save + post = blog.blog_posts.first + post.body = "The sea lions have left the pier. Earthquake imminent?" + post.save on_insert_calls.should be_empty - on_update_calls.length.should == grain_posts.size - on_update_calls.all? {|call| call[0][Blog] == blog && call[1].wire_representation == {"title" => "Did you mean Barbie?"}}.should be_true - Set.new(on_update_calls.map {|call| call[0][BlogPost]}).should == Set.new(grain_posts.all) + on_update_calls.length.should == 1 + on_update_calls.first[0][Blog].should == blog + on_update_calls.first[0][BlogPost].should == post + on_update_calls.first[1].wire_representation.should == { 'body' => "The sea lions have left the pier. Earthquake imminent?" } + on_remove_calls.should be_empty end end - end - describe "when a record in right operand is updated" do - describe "when the update causes some composite tuples to become present in the join" do - it "fires #on_insert events with all composite tuples that are now present in the join" do - post_1 = BlogPost.create(:blog_id => "fun") - post_2 = BlogPost.create(:blog_id => "fun") + describe "when the update causes some composite tuples to stop being present in the join and others to become present" do + it "fires both #on_remove and #on_insert events" do + grain_blog = Blog.find("grain") + vegetable_blog = Blog.find("vegetable") + grain_post = grain_blog.blog_posts.first - blog = Blog.unsafe_create(:id => "misery") - blog.id = "fun" - blog.save + grain_post.blog_id = "vegetable" + grain_post.save - on_insert_calls.length.should == 2 - on_insert_calls.all? {|composite_tuple| composite_tuple[Blog] == blog }.should be_true - Set.new(on_insert_calls.map {|composite_tuple| composite_tuple[BlogPost]}).should == Set.new([post_1, post_2]) + on_insert_calls.length.should == 1 + on_insert_calls.first[Blog].should == vegetable_blog + on_insert_calls.first[BlogPost].should == grain_post on_update_calls.should be_empty - on_remove_calls.should be_empty + + on_remove_calls.length.should == 1 + on_remove_calls.first[Blog].should == grain_blog + on_remove_calls.first[BlogPost].should == grain_post end end - -# describe "when the update causes some composite tuples to stop being present in the join" do -# it "fires #on_remove events with all composite tuples that were removed from the join" do -# blog = Blog.find("grain") -# grain_posts = blog.blog_posts -# blog.id = "crapola" -# blog.save -# -# on_insert_calls.should be_empty -# on_update_calls.should be_empty -# on_remove_calls.length.should == grain_posts.size -# on_remove_calls.all? {|composite_tuple| composite_tuple[Blog] == blog }.should be_true -# Set.new(on_remove_calls.map {|composite_tuple| composite_tuple[BlogPost]}).should == Set.new(grain_posts.all) -# end -# end -# -# describe "when the update causes some composite tuples to stop being present in the join and others to become present" do -# it "fires both #on_remove and #on_insert events" do -# post_1 = BlogPost.create(:blog_id => "fun") -# post_2 = BlogPost.create(:blog_id => "fun") -# -# blog = Blog.find("grain") -# grain_posts = blog.blog_posts -# blog.id = "fun" -# blog.save -# -# on_insert_calls.length.should == 2 -# on_insert_calls.all? {|composite_tuple| composite_tuple[Blog] == blog }.should be_true -# Set.new(on_insert_calls.map {|composite_tuple| composite_tuple[BlogPost]}).should == Set.new([post_1, post_2]) -# -# on_update_calls.should be_empty -# -# on_remove_calls.length.should == grain_posts.size -# on_remove_calls.all? {|composite_tuple| composite_tuple[Blog] == blog }.should be_true -# Set.new(on_remove_calls.map {|composite_tuple| composite_tuple[BlogPost]}).should == Set.new(grain_posts.all) -# end -# end end describe "when a record is removed from the left operand" do @@ -291,7 +314,7 @@ module Relations end end - describe "when a record is removed from the left operand" do + describe "when a record is removed from the right operand" do it "fires #on_remove events with all composite tuples that were previously in the join" do blog = Blog.find("grain") blog_post = blog.blog_posts.first