Permalink
Browse files

Generating immutable keys for tuples to store them in the correct pla…

…ce in the storedTuples of each relation. For each operation, going to pass a newKey and oldKey through the event chain in case an update mutated fields that are needed to locate the record's previous location
  • Loading branch information...
1 parent 9671fab commit c5c12e469a21b1caac39c9788b222d4b1cf99767 @nathansobo committed Jan 3, 2011
@@ -4,6 +4,7 @@ _.constructor("Monarch.Model.Column", {
initialize: function(table, name, type) {
this.table = table;
this.name = name;
+ this.qualifiedName = table.globalName + "." + name;
this.type = type;
},
@@ -11,7 +11,7 @@ _.constructor("Monarch.Model.Relations.InnerJoin", Monarch.Model.Relations.Relat
},
tuples: function() {
- if (this._tuples) return this._tuples.values();
+ if (this.storedTuples) return this.storedTuples.values();
return _.filter(this.cartesianProduct(), function(compositeTuple) {
return this.predicate.evaluate(compositeTuple);
}, this);
@@ -86,32 +86,35 @@ _.constructor("Monarch.Model.Relations.InnerJoin", Monarch.Model.Relations.Relat
this.operandsSubscriptionBundle.add(this.leftOperand.onUpdate(function(leftTuple, changeset) {
_.each(self.rightOperand.tuples(), function(rightTuple) {
var newCompositeTuple = new Monarch.Model.CompositeTuple(leftTuple, rightTuple);
- var extantCompositeTuple = self.findCompositeTupleThatMatches(newCompositeTuple);
+ var extantCompositeTuple = self.storedTuples.find(self.buildSortKey(newCompositeTuple, changeset));
+
if (self.predicate.evaluate(newCompositeTuple)) {
if (extantCompositeTuple) {
self.tupleUpdatedRemotely(extantCompositeTuple, changeset);
} else {
self.tupleInsertedRemotely(newCompositeTuple);
}
} else {
- if (extantCompositeTuple) self.tupleRemovedRemotely(extantCompositeTuple);
+ if (extantCompositeTuple) {
+ self.tupleRemovedRemotely(extantCompositeTuple, changeset);
+ }
}
});
}));
this.operandsSubscriptionBundle.add(this.rightOperand.onUpdate(function(rightTuple, changeset) {
-
_.each(self.leftOperand.tuples(), function(leftTuple) {
var newCompositeTuple = new Monarch.Model.CompositeTuple(leftTuple, rightTuple);
- var extantCompositeTuple = self.findCompositeTupleThatMatches(newCompositeTuple);
+ var extantCompositeTuple = self.storedTuples.find(self.buildSortKey(newCompositeTuple, changeset));
+
if (self.predicate.evaluate(newCompositeTuple)) {
if (extantCompositeTuple) {
self.tupleUpdatedRemotely(extantCompositeTuple, changeset);
} else {
self.tupleInsertedRemotely(newCompositeTuple);
}
} else {
- if (extantCompositeTuple) self.tupleRemovedRemotely(extantCompositeTuple);
+ if (extantCompositeTuple) self.tupleRemovedRemotely(extantCompositeTuple, changeset);
}
})
}));
@@ -39,27 +39,29 @@ _.constructor("Monarch.Model.Relations.Ordering", Monarch.Model.Relations.Relati
// private
tupleInsertedRemotely: function(tuple) {
- var position = this._tuples.insert(tuple)
+ var position = this.storedTuples.insert(this.buildSortKey(tuple), tuple);
this.onInsertNode.publish(tuple, position);
},
- tupleUpdatedRemotely: function($super, tuple, changedFields) {
- var positionMayChange = _.any(changedFields, function(changedField) {
+ tupleUpdatedRemotely: function($super, tuple, changeset) {
+ var positionMayChange = _.any(changeset, function(changedField) {
return this.sortingOnColumn(changedField.column);
}, this);
+
if (!positionMayChange) {
- $super(tuple, changedFields, currentPosition, currentPosition);
+ var currentPosition = this.storedTuples.indexOf(tuple);
+ $super(tuple, changeset, currentPosition, currentPosition);
return;
}
- var oldPosition = this._tuples.remove(tuple);
- var newPosition = this._tuples.insert(tuple);
- $super(tuple, changedFields, newPosition, oldPosition);
+ var oldPosition = this.storedTuples.remove(this.buildSortKey(tuple, changeset));
+ var newPosition = this.storedTuples.insert(this.buildSortKey(tuple), tuple);
+ $super(tuple, changeset, newPosition, oldPosition);
},
- tupleRemovedRemotely: function(record) {
- var position = this._tuples.remove(record);
- this.onRemoveNode.publish(record, position);
+ tupleRemovedRemotely: function(tuple) {
+ var position = this.storedTuples.remove(this.buildSortKey(tuple));
+ this.onRemoveNode.publish(tuple, position);
},
sortingOnColumn: function(column) {
@@ -33,7 +33,7 @@ _.constructor("Monarch.Model.Relations.Projection", Monarch.Model.Relations.Rela
},
tuples: function() {
- if (this._tuples) return this._tuples.values();
+ if (this.storedTuples) return this.storedTuples.values();
this.tuplesByOperandRecordId = {};
return _.map(this.operand.tuples(), function(operandTuple) {
@@ -234,9 +234,11 @@ _.constructor("Monarch.Model.Relations.Relation", {
},
memoizeTuples: function() {
- var tuples = this.buildSkipList();
- tuples.insertAll(this.tuples());
- this._tuples = tuples;
+ var storedTuples = this.buildSkipList();
+ this.each(function(tuple) {
+ storedTuples.insert(this.buildSortKey(tuple), tuple);
+ }, this);
+ this.storedTuples = storedTuples;
},
buildSkipList: function() {
@@ -252,11 +254,11 @@ _.constructor("Monarch.Model.Relations.Relation", {
return function(a, b) {
for(var i = 0; i < length; i++) {
var sortSpecification = sortSpecs[i]
- var column = sortSpecification.column;
+ var columnName = sortSpecification.qualifiedColumnName;
var directionCoefficient = sortSpecification.directionCoefficient;
- var aValue = a.field(column).value();
- var bValue = b.field(column).value();
+ var aValue = a[columnName];
+ var bValue = b[columnName];
if (lessThan(aValue, bValue)) return -1 * directionCoefficient;
else if (lessThan(bValue, aValue)) return 1 * directionCoefficient;
@@ -265,31 +267,53 @@ _.constructor("Monarch.Model.Relations.Relation", {
};
},
- tupleInsertedRemotely: function(record) {
- this._tuples.insert(record)
- this.onInsertNode.publish(record);
+ buildSortKey: function(tuple, changeset) {
+ var sortKey = {};
+ _.each(this.sortSpecifications, function(sortSpec) {
+ var column = sortSpec.column;
+ var columnName = sortSpec.columnName;
+ var qualifiedColumnName = sortSpec.qualifiedColumnName;
+
+ if (changeset && changeset[columnName] && changeset[columnName].column === column) {
+ sortKey[qualifiedColumnName] = changeset[columnName].oldValue;
+ } else {
+ sortKey[qualifiedColumnName] = tuple.field(column).value();
+ }
+ });
+ return sortKey;
+ },
+
+ tupleInsertedRemotely: function(tuple, newKey, oldKey) {
+ if (!newKey) newKey = oldKey = this.buildSortKey(tuple);
+ var index = this.storedTuples.insert(newKey, tuple)
+ this.onInsertNode.publish(tuple, index, newKey, oldKey);
},
- tupleUpdatedRemotely: function(record, updateData, newIndex, oldIndex) {
- if (newIndex === undefined) {
- this.onUpdateNode.publish(record, updateData);
- } else {
- this.onUpdateNode.publish(record, updateData, newIndex, oldIndex);
+ tupleUpdatedRemotely: function(tuple, changeset, newKey, oldKey) {
+ if (!newKey) {
+ newKey = this.buildSortKey(tuple);
+ oldKey = this.buildSortKey(tuple, changeset);
}
+
+ var oldIndex = this.storedTuples.remove(oldKey)
+ var newIndex = this.storedTuples.insert(newKey, tuple);
+ this.onUpdateNode.publish(tuple, changeset, newIndex, oldIndex, newKey, oldKey);
},
- tupleUpdatedLocally: function(record, updateData) {
- this.onLocalUpdateNode.publish(record, updateData);
+ tupleRemovedRemotely: function(tuple, changeset, newKey, oldKey) {
+ if (!newKey) newKey = oldKey = this.buildSortKey(tuple);
+
+ var index = this.storedTuples.remove(oldKey);
+ this.onRemoveNode.publish(tuple, index, newKey, oldKey);
},
- tupleRemovedRemotely: function(record) {
- this._tuples.remove(record);
- this.onRemoveNode.publish(record);
+ tupleUpdatedLocally: function(tuple, updateData) {
+ this.onLocalUpdateNode.publish(tuple, updateData);
},
- contains: function(record) {
- if (this._tuples) {
- return this._tuples.find(record) !== undefined;
+ contains: function(record, changeset) {
+ if (this.storedTuples) {
+ return this.storedTuples.find(this.buildSortKey(record, changeset)) !== undefined;
} else {
return _.indexOf(this.tuples(), record) !== -1;
}
@@ -316,7 +340,7 @@ _.constructor("Monarch.Model.Relations.Relation", {
unsubscribeFromOperands: function() {
this.operandsSubscriptionBundle.destroy();
- this._tuples = null;
+ this.storedTuples = null;
},
remoteSubscribe: function() {
@@ -10,8 +10,8 @@ _.constructor("Monarch.Model.Relations.Selection", Monarch.Model.Relations.Relat
},
tuples: function() {
- if (this._tuples) {
- return this._tuples.values();
+ if (this.storedTuples) {
+ return this.storedTuples.values();
}
return _.filter(this.operand.tuples(), function(tuple) {
return this.predicate.evaluate(tuple);
@@ -70,10 +70,10 @@ _.constructor("Monarch.Model.Relations.Selection", Monarch.Model.Relations.Relat
if (this.predicate.evaluate(record)) this.tupleRemovedRemotely(record);
}, this));
- this.operandsSubscriptionBundle.add(this.operand.onUpdate(function(record, changedFields) {
- if (this.contains(record)) {
+ this.operandsSubscriptionBundle.add(this.operand.onUpdate(function(record, changeset) {
+ if (this.contains(record, changeset)) {
if (this.predicate.evaluate(record)) {
- this.tupleUpdatedRemotely(record, changedFields);
+ this.tupleUpdatedRemotely(record, changeset);
} else {
this.tupleRemovedRemotely(record);
}
@@ -10,7 +10,7 @@ _.constructor("Monarch.Model.Relations.Table", Monarch.Model.Relations.Relation,
this.syntheticColumnsByName = {};
this.defineColumn('id', 'key');
this.sortSpecifications = [this.column("id").asc()];
- this._tuples = this.buildSkipList();
+ this.storedTuples = this.buildSkipList();
this.tuplesById = {};
this.initializeEventsSystem();
@@ -52,7 +52,7 @@ _.constructor("Monarch.Model.Relations.Table", Monarch.Model.Relations.Relation,
},
tuples: function() {
- return this._tuples.values();
+ return this.storedTuples.values();
},
find: function(predicateOrId) {
@@ -154,7 +154,7 @@ _.constructor("Monarch.Model.Relations.Table", Monarch.Model.Relations.Relation,
},
clear: function() {
- this._tuples = this.buildSkipList();
+ this.storedTuples = this.buildSkipList();
this.tuplesById = {}
this.onInsertNode = new Monarch.SubscriptionNode();
this.onRemoveNode = new Monarch.SubscriptionNode();
@@ -15,7 +15,7 @@ _.constructor("Monarch.Model.Relations.TableProjection", Monarch.Model.Relations
hasOperands: true,
tuples: function() {
- if (this._tuples) return this._tuples.values();
+ if (this.storedTuples) return this.storedTuples.values();
var tuples = [];
_.each(this.operand.tuples(), function(compositeTuple) {
@@ -9,7 +9,7 @@ _.constructor("Monarch.Model.Relations.Union", Monarch.Model.Relations.Relation,
},
tuples: function() {
- if (this._tuples) return this._tuples.values();
+ if (this.storedTuples) return this.storedTuples.values();
var tuplesByHashCode = {};
@@ -29,11 +29,11 @@ _.constructor("Monarch.Model.Relations.Union", Monarch.Model.Relations.Relation,
// private
subscribeToOperands: function() {
this.operandsSubscriptionBundle.add(this.leftOperand.onInsert(function(record) {
- if (!this.rightOperand.contains(record)) this.tupleInsertedRemotely(record);
+ if (!this.contains(record)) this.tupleInsertedRemotely(record);
}, this));
this.operandsSubscriptionBundle.add(this.rightOperand.onInsert(function(record) {
- if (!this.leftOperand.contains(record)) this.tupleInsertedRemotely(record);
+ if (!this.contains(record)) this.tupleInsertedRemotely(record);
}, this));
this.operandsSubscriptionBundle.add(this.leftOperand.onUpdate(function(record, changes) {
@@ -58,7 +58,6 @@ _.constructor("Monarch.Model.Relations.Union", Monarch.Model.Relations.Relation,
this.lastChanges = changes;
$super(record, changes);
}
-
});
})(Monarch);
@@ -3,6 +3,8 @@
_.constructor("Monarch.Model.SortSpecification", {
initialize: function(column, direction) {
this.column = column;
+ this.columnName = column.name;
+ this.qualifiedColumnName = column.qualifiedName;
this.direction = direction;
this.directionCoefficient = (direction == "desc") ? -1 : 1;
}
@@ -537,7 +537,7 @@ Screw.Unit(function(c) { with(c) {
server.lastPost.simulateSuccess({primary: [null], secondary: []});
expect(Blog.find('recipes')).to(beNull);
- expect(_.any(Blog.table._tuples, function(r) { r === record})).to(beFalse);
+ expect(_.any(Blog.tuples(), function(r) { r === record})).to(beFalse);
expect('recipes' in Blog.table.tuplesById).to(beFalse);
expect(beforeEventsCallback).to(haveBeenCalled);
@@ -215,7 +215,6 @@ Screw.Unit(function(c) { with(c) {
var updatedTuple = updateHandler.mostRecentArgs[0];
var changedAttributes = updateHandler.mostRecentArgs[1];
-
expect(updatedTuple.leftTuple).to(eq, blog2);
expect(updatedTuple.rightTuple).to(eq, post3);
@@ -229,7 +228,7 @@ Screw.Unit(function(c) { with(c) {
context("when the CompositeTuple no longer matches #predicate after the update", function() {
it("triggers only #onRemove handlers with the updated CompositeTuple", function() {
- blog2.update({id: "booboo"});
+ blog2.remotelyUpdated({id: "booboo"});
expect(removeHandler).to(haveBeenCalled, once);
expect(removeHandler.mostRecentArgs[0].leftTuple).to(eq, blog2);
expect(removeHandler.mostRecentArgs[0].rightTuple).to(eq, post3);
@@ -390,26 +389,26 @@ Screw.Unit(function(c) { with(c) {
expect(leftOperand.hasSubscribers()).to(beFalse);
expect(rightOperand.hasSubscribers()).to(beFalse);
- expect(join._tuples).to(beNull);
+ expect(join.storedTuples).to(beNull);
var subscription = join[eventType].call(join, function() {});
expect(leftOperand.hasSubscribers()).to(beTrue);
expect(rightOperand.hasSubscribers()).to(beTrue);
- expect(join._tuples).toNot(beNull);
+ expect(join.storedTuples).toNot(beNull);
subscription.destroy();
expect(leftOperand.hasSubscribers()).to(beFalse);
expect(rightOperand.hasSubscribers()).to(beFalse);
- expect(join._tuples).to(beNull);
+ expect(join.storedTuples).to(beNull);
join.onUpdate(function() {});
expect(leftOperand.hasSubscribers()).to(beTrue);
expect(rightOperand.hasSubscribers()).to(beTrue);
- expect(join._tuples).toNot(beNull);
+ expect(join.storedTuples).toNot(beNull);
});
});
});
Oops, something went wrong.

0 comments on commit c5c12e4

Please sign in to comment.