diff --git a/lib/indexes.js b/lib/indexes.js index d39ece0..8271dbf 100644 --- a/lib/indexes.js +++ b/lib/indexes.js @@ -1,9 +1,18 @@ -var BinarySearchTree = require('binary-search-tree').BinarySearchTree; +var BinarySearchTree = require('binary-search-tree').BinarySearchTree + , model = require('./model') + ; + +/** + * We can't use the one in model here since it doesn't work for arrays + */ +function checkValueEquality (a, b) { + return model.compareThings(a, b) === 0; +} /** * Create a new index - * @param {String} options.fieldName On which field should the index apply + * @param {String} options.fieldName On which field should the index apply (can use dot notation to index on sub fields) * @param {Datastore} options.datastore Datastore on which the index is created * @param {Boolean} options.unique Optional, enforce a unique constraint (default: false) * @param {Boolean} options.sparse Optional, allow a sparse index (we can have documents for which fieldName is undefined) (default: false) @@ -14,10 +23,28 @@ function Index (options) { this.unique = options.unique || false; this.sparse = options.unique || false; - if (this.sparse) { this.fieldUndefined = []; } // Will store all elements for which the indexed field is not defined + if (this.sparse) { this.unindexedDocs = []; } + + this.tree = new BinarySearchTree({ unique: this.unique, compareKeys: model.compareThings, checkValueEquality: checkValueEquality }); } +/** + * Insert a new document in the index (synchronously) + */ +Index.prototype.insert = function (doc) { + var key = model.getDotValue(doc, this.fieldName); + + // We don't index documents that don't contain the field if the index is sparse + if (key === undefined && this.sparse) { + this.unindexedDocs.push(doc); + return; + } + + this.tree.insert(key, doc); +}; + + // Interface diff --git a/lib/model.js b/lib/model.js index e9f6a80..29b4161 100644 --- a/lib/model.js +++ b/lib/model.js @@ -156,16 +156,21 @@ function compareArrays (a, b) { /** - * Compare things + * Compare { things U undefined } * Things are defined as any native types (string, number, boolean, null, date) and objects + * We need to compare with undefined as it will be used in indexes * In the case of objects and arrays, we compare the serialized versions - * If two objects dont have the same type, the (arbitrary) type hierarchy is: null, number, strings, boolean, dates, arrays, objects + * If two objects dont have the same type, the (arbitrary) type hierarchy is: undefined, null, number, strings, boolean, dates, arrays, objects * Return -1 if a < b, 1 if a > b and 0 if a = b (note that equality here is NOT the same as defined in areThingsEqual!) */ function compareThings (a, b) { var aKeys, bKeys, comp, i; - // null is less than everything except null + // undefined + if (a === undefined) { return b === undefined ? 0 : -1; } + if (b === undefined) { return a === undefined ? 0 : 1; } + + // null if (a === null) { return b === null ? 0 : -1; } if (b === null) { return a === null ? 0 : 1; } diff --git a/test/model.test.js b/test/model.test.js index 23c27e7..e1d243b 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -331,7 +331,18 @@ describe('Model', function () { describe('Comparing things', function () { - it('null is less than everything except null', function () { + it('undefined is the smallest', function () { + var otherStuff = [null, "string", "", -1, 0, 5.3, 12, true, false, new Date(12345), {}, { hello: 'world' }, [], ['quite', 5]]; + + model.compareThings(undefined, undefined).should.equal(0); + + otherStuff.forEach(function (stuff) { + model.compareThings(undefined, stuff).should.equal(-1); + model.compareThings(stuff, undefined).should.equal(1); + }); + }); + + it('Then null', function () { var otherStuff = ["string", "", -1, 0, 5.3, 12, true, false, new Date(12345), {}, { hello: 'world' }, [], ['quite', 5]]; model.compareThings(null, null).should.equal(0); @@ -342,7 +353,7 @@ describe('Model', function () { }); }); - it('After null, numbers are the smallest', function () { + it('Then numbers', function () { var otherStuff = ["string", "", true, false, new Date(4312), {}, { hello: 'world' }, [], ['quite', 5]] , numbers = [-12, 0, 12, 5.7];