Permalink
Browse files

Union integrated with skip list / sort keys

  • Loading branch information...
1 parent 4c47662 commit 14dc39a69ba4548f9f59324ae0404db3e81215ee @nathansobo committed Jan 4, 2011
Showing with 109 additions and 72 deletions.
  1. +40 −30 lib/monarch/model/relations/union.js
  2. +69 −42 spec/monarch/model/relations/union_spec.js
View
70 lib/monarch/model/relations/union.js
@@ -27,39 +27,49 @@ _.constructor("Monarch.Model.Relations.Union", Monarch.Model.Relations.Relation,
surfaceTables: function() {
return this.leftOperand.surfaceTables();
},
-
+
// private
- subscribeToOperands: function() {
- this.operandsSubscriptionBundle.add(this.leftOperand.onInsert(function(record) {
- if (!this.contains(record)) this.tupleInsertedRemotely(record);
- }, this));
-
- this.operandsSubscriptionBundle.add(this.rightOperand.onInsert(function(record) {
- if (!this.contains(record)) this.tupleInsertedRemotely(record);
- }, this));
-
- this.operandsSubscriptionBundle.add(this.leftOperand.onUpdate(function(record, changes) {
- if (this.contains(record)) this.tupleUpdatedRemotely(record, changes);
- }, this));
-
- this.operandsSubscriptionBundle.add(this.rightOperand.onUpdate(function(record, changes) {
- if (this.contains(record)) this.tupleUpdatedRemotely(record, changes);
- }, this));
-
- this.operandsSubscriptionBundle.add(this.leftOperand.onRemove(function(record) {
- if (!this.rightOperand.contains(record)) this.tupleRemovedRemotely(record);
- }, this));
-
- this.operandsSubscriptionBundle.add(this.rightOperand.onRemove(function(record) {
- if (!this.leftOperand.contains(record)) this.tupleRemovedRemotely(record);
- }, this));
+
+ onLeftOperandInsert: function(tuple, index, newKey, oldKey) {
+ if (!this.findByKey(oldKey)) this.tupleInsertedRemotely(tuple);
+ },
+
+ onRightOperandInsert: function(tuple, index, newKey, oldKey) {
+ if (!this.findByKey(oldKey)) this.tupleInsertedRemotely(tuple);
+ },
+
+ onLeftOperandUpdate: function(tuple, changeset, newIndex, oldIndex, newKey, oldKey) {
+ if (this.lastChangeset === changeset) return;
+ this.lastChangeset = changeset;
+ this.tupleUpdatedRemotely(tuple, changeset, newKey, oldKey);
+ },
+
+ onRightOperandUpdate: function(tuple, changeset, newIndex, oldIndex, newKey, oldKey) {
+ if (this.lastChangeset === changeset) return;
+ this.lastChangeset = changeset;
+ this.tupleUpdatedRemotely(tuple, changeset, newKey, oldKey);
+ },
+
+ onLeftOperandRemove: function(tuple, index, newKey, oldKey) {
+ if (!this.rightOperand.find(tuple.id())) this.tupleRemovedRemotely(tuple, newKey, oldKey);
+ },
+
+ onRightOperandRemove: function(tuple, index, newKey, oldKey) {
+ if (!this.leftOperand.find(tuple.id())) this.tupleRemovedRemotely(tuple, newKey, oldKey);
},
- tupleUpdatedRemotely: function($super, record, changes) {
- if (this.lastChanges == changes) return;
- this.lastChanges = changes;
- $super(record, changes);
- }
+ // not implemented yet
+ onLeftOperandDirty: function() {},
+ onRightOperandDirty: function() {},
+
+ onLeftOperandClean: function() {},
+ onRightOperandClean: function() {},
+
+ onLeftOperandInvalid: function() {},
+ onRightOperandInvalid: function() {},
+
+ onLeftOperandValid: function() {},
+ onRightOperandValid: function() {}
});
})(Monarch);
View
111 spec/monarch/model/relations/union_spec.js
@@ -29,14 +29,15 @@ Screw.Unit(function(c) { with(c) {
});
describe("event handling", function() {
- var user, union, insertCallback, updateCallback, removeCallback;
- useLocalFixtures();
+ var user, blog, union, insertCallback, updateCallback, removeCallback;
before(function() {
- user = User.find("jan");
+ user = User.createFromRemote({id: 1});
+ blog = user.blogs().createFromRemote({id: 1});
+
var leftOperand = user.blogPosts();
var rightOperand = user.favoriteBlogPosts();
- union = new Monarch.Model.Relations.Union(leftOperand, rightOperand);
+ union = leftOperand.union(rightOperand);
insertCallback = mockFunction("insertCallback");
updateCallback = mockFunction("updateCallback");
@@ -60,23 +61,26 @@ Screw.Unit(function(c) { with(c) {
describe("when a record is inserted in the left operand", function() {
context("if the record is not present in the right operand", function() {
- it("triggers insert callbacks with the record", function() {
- var post = BlogPost.find("frying");
- post.remotelyUpdated({blogId: "motorcycle"})
+ it("triggers an insert event with the record", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ var sortKey = union.buildSortKey(record);
- expect(insertCallback).to(haveBeenCalled, withArgs(post));
+ expect(insertCallback).to(haveBeenCalled, withArgs(record, 0, sortKey, sortKey));
expect(updateCallback).toNot(haveBeenCalled);
expect(removeCallback).toNot(haveBeenCalled);
});
});
context("if the record is present in the right operand", function() {
- it("does not trigger an insert callbacks", function() {
- var post = BlogPost.find("frying");
- user.favoritings().createFromRemote({blogPostId: post.id()});
+ it("does not trigger an insert event", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 2});
+ user.favoritings().createFromRemote({blogPostId: 1});
+
clearCallbackMocks();
- post.remotelyUpdated({blogId: "motorcycle"})
+ // update causes an insert into the user's blog post selection, but its already a favorite so no event
+ record.remotelyUpdated({blogId: 1});
+
expect(insertCallback).toNot(haveBeenCalled);
// update callback gets called as an artifact of how we insert into the left operand
expect(updateCallback).to(haveBeenCalled, once);
@@ -87,62 +91,81 @@ Screw.Unit(function(c) { with(c) {
describe("when a record is inserted in the right operand", function() {
context("if the record is not present in the left operand", function() {
- it("triggers insert callbacks with the record", function() {
- var post = BlogPost.find("frying");
- user.favoritings().createFromRemote({blogPostId: post.id()});
- expect(insertCallback).to(haveBeenCalled, withArgs(post));
+ it("triggers an insert event with the record", function() {
+ var record = BlogPost.createFromRemote({id: 1});
+ var sortKey = union.buildSortKey(record);
+
+ user.favoritings().createFromRemote({blogPostId: 1});
+ expect(insertCallback).to(haveBeenCalled, withArgs(record, 0, sortKey, sortKey));
expect(updateCallback).toNot(haveBeenCalled);
expect(removeCallback).toNot(haveBeenCalled);
});
});
context("if the record is present in the left operand", function() {
it("does not trigger any callbacks", function() {
- user.favoritings().createFromRemote({blogPostId: "helmet"});
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ clearCallbackMocks();
+
+ user.favoritings().createFromRemote({blogPostId: 1});
expectNoCallbacksToHaveBeenCalled();
});
});
});
describe("when a record is updated in the left operand", function() {
context("if the record is not present in the right operand", function() {
- it("triggers update callbacks with the record", function() {
- var post = user.blogPosts().first();
- post.remotelyUpdated({name: "New Name"});
+ it("triggers an update event with the record", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ var sortKey = union.buildSortKey(record);
+
+ clearCallbackMocks();
+
+ record.remotelyUpdated({name: "New Name"});
expect(updateCallback).to(haveBeenCalled, once);
- expect(updateCallback.mostRecentArgs[0]).to(eq, post);
+ expect(updateCallback.mostRecentArgs[0]).to(eq, record);
+ // skip verification of changeset because it's a pain
+ expect(updateCallback.mostRecentArgs[2]).to(eq, 0);
+ expect(updateCallback.mostRecentArgs[3]).to(eq, 0);
+ expect(updateCallback.mostRecentArgs[4]).to(equal, sortKey);
+ expect(updateCallback.mostRecentArgs[5]).to(equal, sortKey);
+
expect(insertCallback).toNot(haveBeenCalled);
expect(removeCallback).toNot(haveBeenCalled);
});
});
context("if the record is present in the right operand", function() {
- it("triggers update callbacks with the record, but not twice", function() {
- var post = user.blogPosts().first();
- user.favoritings().createFromRemote({blogPostId: post.id()})
+ it("triggers an update event with the record, but not twice", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ user.favoritings().createFromRemote({blogPostId: 1})
clearCallbackMocks();
- post.update({name: "New Name"});
+ record.update({name: "New Name"});
expect(updateCallback).to(haveBeenCalled, once);
});
});
});
describe("when a record is removed from the left operand", function() {
context("if the record is not present in the right operand", function() {
- it("triggers remove callbacks with the record", function() {
- var post = user.blogPosts().first();
- expect(union.contains(post)).to(beTrue);
- post.remotelyDestroyed();
- expect(removeCallback).to(haveBeenCalled, once);
+ it("triggers a remove event with the record", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ var sortKey = union.buildSortKey(record);
+ clearCallbackMocks();
+
+ record.remotelyDestroyed();
+ expect(removeCallback).to(haveBeenCalled, withArgs(record, 0, sortKey, sortKey));
});
});
context("if the record is present in the right operand", function() {
- it("does not trigger any callbacks", function() {
- var post = user.blogPosts().first();
- user.favoritings().createFromRemote({blogPostId: post.id()});
- post.remotelyUpdated({blogId: "recipes"});
+ it("does not trigger a remove event", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ user.favoritings().createFromRemote({blogPostId: 1})
+ clearCallbackMocks();
+
+ record.remotelyUpdated({blogId: 100});
expect(removeCallback).toNot(haveBeenCalled);
});
});
@@ -151,19 +174,23 @@ Screw.Unit(function(c) { with(c) {
describe("when a record is removed from the right operand", function() {
context("if the record is not present in the left operand", function() {
it("triggers remove callbacks with the record", function() {
- var post = BlogPost.find("frying");
- var favoriting = user.favoritings().createFromRemote({blogPostId: post.id()});
+ var record = BlogPost.createFromRemote({id: 1, blogId: 100});
+ var sortKey = union.buildSortKey(record);
+ var favoriting = user.favoritings().createFromRemote({blogPostId: 1})
+ clearCallbackMocks();
+
favoriting.destroy();
- expect(removeCallback).to(haveBeenCalled, withArgs(post));
+ expect(removeCallback).to(haveBeenCalled, withArgs(record, 0, sortKey, sortKey));
});
});
- context("it does not trigger any callbacks", function() {
- it("triggers insert callbacks with the record", function() {
- var post = user.blogPosts().first();
- var favoriting = user.favoritings().createFromRemote({blogPostId: post.id()});
+ context("if the record is present in the left operand", function() {
+ it("does not trigger a remove event", function() {
+ var record = BlogPost.createFromRemote({id: 1, blogId: 1});
+ var favoriting = user.favoritings().createFromRemote({blogPostId: 1})
clearCallbackMocks();
- favoriting.destroy();
+
+ favoriting.remotelyDestroyed();
expect(removeCallback).toNot(haveBeenCalled);
});
});

0 comments on commit 14dc39a

Please sign in to comment.