Browse files

Added sortSpecifications to every relation and building a comparator …

…for that relation's skip list based on them. Still have 2 failures... need to introduce immutable keys
  • Loading branch information...
1 parent 58c6220 commit 89e536827aa3079129ef5a91d285e76dc0fae64e @nathansobo committed Dec 31, 2010
View
2 lib/monarch/model/record.js
@@ -9,7 +9,7 @@
inherited: function(subconstructor) {
subconstructor.table = new Monarch.Model.Relations.Table(this.determineGlobalName(subconstructor), subconstructor);
- subconstructor.column("id", "key");
+ subconstructor.generateColumnAccessors(subconstructor.table.column('id'));
subconstructor.relationDefinitions = [];
Repository.registerTable(subconstructor.table);
},
View
1 lib/monarch/model/relations/difference.js
@@ -4,6 +4,7 @@ _.constructor("Monarch.Model.Relations.Difference", Monarch.Model.Relations.Rela
initialize: function(leftOperand, rightOperand) {
this.leftOperand = leftOperand;
this.rightOperand = rightOperand;
+ this.sortSpecifications = leftOperand.sortSpecifications;
this.initializeEventsSystem();
},
View
1 lib/monarch/model/relations/inner_join.js
@@ -6,6 +6,7 @@ _.constructor("Monarch.Model.Relations.InnerJoin", Monarch.Model.Relations.Relat
this.leftOperand = leftOperand;
this.rightOperand = rightOperand;
this.predicate = predicate;
+ this.sortSpecifications = leftOperand.sortSpecifications.concat(rightOperand.sortSpecifications);
this.initializeEventsSystem();
},
View
25 lib/monarch/model/relations/ordering.js
@@ -7,33 +7,12 @@ _.constructor("Monarch.Model.Relations.Ordering", Monarch.Model.Relations.Relati
initialize: function(operand, sortSpecifications) {
this.operand = operand;
- this.sortSpecifications = sortSpecifications;
-
- this.comparator = _.bind(function(a, b) {
- // null and undefined are treated as infinity
- function lessThan(a, b) {
- if ((a === null || a === undefined) && b !== null && b !== undefined) return false;
- if ((b === null || b === undefined) && a !== null && a !== undefined) return true;
- return a < b;
- }
-
- for(var i = 0; i < this.sortSpecifications.length; i++) {
- var sortSpecification = this.sortSpecifications[i]
- var column = sortSpecification.column;
- var directionCoefficient = sortSpecification.directionCoefficient;
-
- var aValue = a.field(column).value();
- var bValue = b.field(column).value();
-
- if (lessThan(aValue, bValue)) return -1 * directionCoefficient;
- else if (lessThan(bValue, aValue)) return 1 * directionCoefficient;
- }
- return 0;
- }, this);
+ this.sortSpecifications = sortSpecifications.concat(operand.sortSpecifications);
this.initializeEventsSystem();
},
tuples: function() {
+ if (!this.comparator) this.comparator = this.buildComparator();
return this.operand.tuples().sort(this.comparator);
},
View
5 lib/monarch/model/relations/projection.js
@@ -8,6 +8,11 @@ _.constructor("Monarch.Model.Relations.Projection", Monarch.Model.Relations.Rela
this.projectedColumnsByName[projectedColumn.name()] = projectedColumn;
}, this);
+
+ this.sortSpecifications = _.filter(operand.sortSpecifications, function(sortSpec) {
+ return this.column(sortSpec.column.name)
+ }, this);
+
this.tupleConstructor = _.constructor(Monarch.Model.Tuple);
this.tupleConstructor.projectedColumnsByName = this.projectedColumnsByName;
this.tupleConstructor.initializeFieldReaders();
View
22 lib/monarch/model/relations/relation.js
@@ -240,9 +240,31 @@ _.constructor("Monarch.Model.Relations.Relation", {
},
buildSkipList: function() {
+ if (!this.comparator) this.comparator = this.buildComparator();
return new Monarch.SkipList(this.comparator);
},
+ buildComparator: function() {
+ var sortSpecs = this.sortSpecifications;
+ var length = sortSpecs.length;
+ var lessThan = _.nullSafeLessThan;
+
+ return function(a, b) {
+ for(var i = 0; i < length; i++) {
+ var sortSpecification = sortSpecs[i]
+ var column = sortSpecification.column;
+ var directionCoefficient = sortSpecification.directionCoefficient;
+
+ var aValue = a.field(column).value();
+ var bValue = b.field(column).value();
+
+ if (lessThan(aValue, bValue)) return -1 * directionCoefficient;
+ else if (lessThan(bValue, aValue)) return 1 * directionCoefficient;
+ }
+ return 0;
+ };
+ },
+
tupleInsertedRemotely: function(record) {
this._tuples.insert(record)
this.onInsertNode.publish(record);
View
1 lib/monarch/model/relations/selection.js
@@ -5,6 +5,7 @@ _.constructor("Monarch.Model.Relations.Selection", Monarch.Model.Relations.Relat
initialize: function(operand, predicate) {
this.operand = operand;
this.predicate = predicate;
+ this.sortSpecifications = operand.sortSpecifications;
this.initializeEventsSystem();
},
View
8 lib/monarch/model/relations/table.js
@@ -8,6 +8,8 @@ _.constructor("Monarch.Model.Relations.Table", Monarch.Model.Relations.Relation,
this.recordConstructor = recordConstructor;
this.columnsByName = {};
this.syntheticColumnsByName = {};
+ this.defineColumn('id', 'key');
+ this.sortSpecifications = [this.column("id").asc()];
this._tuples = this.buildSkipList();
this.tuplesById = {};
@@ -16,12 +18,6 @@ _.constructor("Monarch.Model.Relations.Table", Monarch.Model.Relations.Relation,
this.onResumeEventsNode = new Monarch.SubscriptionNode();
},
- comparator: function(a, b) {
- if (a.id() < b.id()) return -1;
- if (a.id() > b.id()) return 1;
- return 0;
- },
-
defineColumn: function(name, type) {
return this.columnsByName[name] = new Monarch.Model.Column(this, name, type);
},
View
1 lib/monarch/model/relations/table_projection.js
@@ -8,6 +8,7 @@ _.constructor("Monarch.Model.Relations.TableProjection", Monarch.Model.Relations
initialize: function(operand, projectedTable) {
this.operand = operand;
this.projectedTable = projectedTable;
+ this.sortSpecifications = projectedTable.sortSpecifications; // this should actually be based on the operand, but we have to remove columns projected away
this.initializeEventsSystem();
},
View
1 lib/monarch/model/relations/union.js
@@ -4,6 +4,7 @@ _.constructor("Monarch.Model.Relations.Union", Monarch.Model.Relations.Relation,
initialize: function(leftOperand, rightOperand) {
this.leftOperand = leftOperand;
this.rightOperand = rightOperand;
+ this.sortSpecifications = leftOperand.sortSpecifications;
this.initializeEventsSystem();
},
View
3 lib/monarch/model/tuple.js
@@ -23,6 +23,9 @@ _.constructor("Monarch.Model.Tuple", {
projectedColumn = projectedColumnOrName;
}
+
+ if (!projectedColumn.column) throw new Error("NULL POINTER EXCEPTION WILL HAPPEN LATeER");
+
return this.operandRecord.field(projectedColumn.column);
},
View
7 lib/monarch/skip_list.js
@@ -1,7 +1,8 @@
(function(Monarch) {
_.constructor("Monarch.SkipList", {
- initialize: function() {
+ initialize: function(comparator) {
+ this.comparator = comparator || this.defaultComparator;
this.maxLevels = 8;
this.p = 0.25;
this.currentLevel = 0;
@@ -136,6 +137,10 @@ _.constructor("Monarch.SkipList", {
if (b === this.minusInfinity) return (a === this.minusInfinity) ? 0 : 1;
if (a === this.plusInfinity) return (b === this.plusInfinity) ? 0 : 1;
if (b === this.plusInfinity) return (a === this.plusInfinity) ? 0 : -1;
+ return this.comparator(a, b);
+ },
+
+ defaultComparator: function(a, b) {
if (a < b) return - 1;
if (a > b) return 1;
return 0;
View
8 lib/monarch/underscore_extensions.js
@@ -48,6 +48,12 @@ _.mixin({
sum += array[i];
}
return sum;
- }
+ },
+ // null and undefined are treated like infinity to sort null values toward the end
+ nullSafeLessThan: function(a, b) {
+ if ((a === null || a === undefined) && b !== null && b !== undefined) return false;
+ if ((b === null || b === undefined) && a !== null && a !== undefined) return true;
+ return a < b;
+ }
});
View
2 spec/monarch/model/record_spec.js
@@ -112,7 +112,7 @@ Screw.Unit(function(c) { with(c) {
var user = User.createFromRemote({id: "jerry"});
var ordering = user.blogs();
expect(ordering.constructor).to(eq, Monarch.Model.Relations.Ordering);
- expect(ordering.sortSpecifications.length).to(eq, 2);
+ expect(ordering.sortSpecifications.length).to(eq, 3); // because sorting by id last is implicit
expect(ordering.sortSpecifications[0].column).to(eq, Blog.name_);
expect(ordering.sortSpecifications[0].direction).to(eq, "desc");
expect(ordering.sortSpecifications[1].column).to(eq, Blog.userId);
View
5 spec/monarch/model/relations/inner_join_spec.js
@@ -126,12 +126,7 @@ Screw.Unit(function(c) { with(c) {
context("when a tuple is inserted into the right operand", function() {
context("when the insertion causes #carteseanProduct to contain a new CompositeTuple that matches the predicate", function() {
it("triggers #onInsert handlers with the new CompositeTuple", function() {
-
- console.debug(leftOperand.tuples());
-
var blogPost = blog1.blogPosts().createFromRemote()
-
-
expect(insertHandler).to(haveBeenCalled, once);
var compositeTuple = insertHandler.mostRecentArgs[0];
expect(compositeTuple.leftTuple).to(eq, blog1);
View
2 spec/monarch/model/relations/ordering_spec.js
@@ -62,7 +62,7 @@ Screw.Unit(function(c) { with(c) {
it("triggers #onInsert callbacks with the inserted tuple and its index", function() {
var record = User.createFromRemote({id: 5, age: 2, fullName: "D"});
expect(insertCallback).to(haveBeenCalled, withArgs(record, 3));
- expect(ordering._tuples[3]).to(eq, record);
+ expect(ordering._tuples.at(3)).to(eq, record);
});
});

0 comments on commit 89e5368

Please sign in to comment.