Comparing version 1.3.0 to 1.3.1
1.3.1 / 2011-04-27 | ||
=================== | ||
* fixed; setting a property on an embedded array no longer overwrites entire array (GH-310) | ||
* fixed; setting nested properties works when sibling prop is named "type" | ||
* fixed; isModified is now much finer grained when .set() is used (GH-323) | ||
* fixed; mongoose.model() and connection.model() now return the Model (GH-308, GH-305) | ||
* fixed; can now use $gt, $lt, $gte, $lte with String schema types (GH-317) | ||
* fixed; .lowercase() -> .toLowerCase() in pluralize() | ||
* fixed; updating an embedded document by index works (GH-334) | ||
* changed; .save() now passes the instance to the callback (GH-294, GH-264) | ||
* added; can now query system.profile and system.indexes collections | ||
* added; db.model('system.profile') is now included as a default Schema | ||
* added; db.setProfiling(level, ms, callback) | ||
* added; Query#hint() support | ||
* added; more tests | ||
* updated node-mongodb-native to 0.9.3 | ||
1.3.0 / 2011-04-19 | ||
@@ -3,0 +21,0 @@ =================== |
@@ -11,2 +11,3 @@ | ||
, Model = require('./model') | ||
, Schema = require('./schema') | ||
, Collection = require(driver + '/collection'); | ||
@@ -316,4 +317,10 @@ | ||
Connection.prototype.model = function (name, collection) { | ||
Connection.prototype.model = function (name, schema, collection) { | ||
if (!(schema instanceof Schema)) { | ||
collection = schema; | ||
schema = null; | ||
} | ||
collection || (collection = utils.toCollectionName(name)); | ||
// look up models for the collection | ||
@@ -323,8 +330,8 @@ if (!this.models[collection]) | ||
if (!this.models[collection][name]){ | ||
var model = this.base.model(name, null, collection, true) | ||
if (!this.models[collection][name]) { | ||
var model = this.base.model(name, schema, collection, true) | ||
, Model; | ||
if (model.prototype.connection != this){ | ||
function Model (){ | ||
Model = function Model (){ | ||
model.apply(this, arguments); | ||
@@ -342,3 +349,3 @@ }; | ||
} | ||
return this.models[collection][name]; | ||
@@ -348,2 +355,53 @@ }; | ||
/** | ||
* Set profiling level. | ||
* | ||
* @param {Int|String} level - Either off (0), slow (1), or all (2) | ||
* @param {Int} [ms] If profiling `level` is set to 1, this determines | ||
* the threshold in milliseconds above which queries | ||
* will be logged. Defaults to 100. (optional) | ||
* @param {Function} callback | ||
* @api public | ||
*/ | ||
Connection.prototype.setProfiling = function (level, ms, callback) { | ||
if (!callback) callback = ms, ms = 100; | ||
var cmd = {}; | ||
switch (level) { | ||
case 0: | ||
case 'off': | ||
cmd.profile = 0; | ||
break; | ||
case 1: | ||
case 'slow': | ||
cmd.profile = 1; | ||
if ('number' !== typeof ms) { | ||
ms = parseInt(ms, 10); | ||
if (isNaN(ms)) ms = 100; | ||
} | ||
cmd.slowms = ms; | ||
break; | ||
case 2: | ||
case 'all': | ||
cmd.profile = 2; | ||
break; | ||
default: | ||
return callback(new Error('Invalid profiling level: '+ level)); | ||
} | ||
this.db.executeDbCommand(cmd, function (err, resp) { | ||
if (err) return callback(err); | ||
var doc = resp.documents[0]; | ||
err = 1 === doc.ok | ||
? null | ||
: new Error('Could not set profiling level to: '+ level) | ||
callback(err, doc); | ||
}); | ||
}; | ||
/** | ||
* Module exports. | ||
@@ -350,0 +408,0 @@ */ |
@@ -16,3 +16,4 @@ | ||
, clone = utils.clone | ||
, ActiveRoster = utils.StateMachine.ctor('require', 'modify', 'init'); | ||
, ActiveRoster = utils.StateMachine.ctor('require', 'modify', 'init') | ||
, deepEqual = utils.deepEqual; | ||
@@ -34,2 +35,3 @@ /** | ||
this.saveError = null; | ||
this.isNew = true; | ||
if (obj) this.set(obj); | ||
@@ -39,3 +41,2 @@ this.pres = {}; | ||
this.doQueue(); | ||
this.isNew = true; | ||
this.errors = undefined; | ||
@@ -117,3 +118,8 @@ }; | ||
for (var i in obj){ | ||
var keys = Object.keys(obj) | ||
, len = keys.length | ||
, i; | ||
while (len--) { | ||
i = keys[len]; | ||
var path = prefix + i | ||
@@ -187,3 +193,3 @@ , schema = self.schema.path(path); | ||
* @param {String/Object} key path, or object | ||
* @param {Object} value, or undefined if first parameter is an object | ||
* @param {Object} value, or undefined or a prefix if first parameter is an object | ||
* @param {Boolean} whether to apply transformations: cast, setters (true) | ||
@@ -224,3 +230,2 @@ * @param {Boolean} whether to mark dirty (true) | ||
// TODO: do actual checking to see if the value changed | ||
var schema = this.schema.path(path) | ||
@@ -239,21 +244,23 @@ , parts = path.split('.') | ||
// Else mongodb throws: "LEFT_SUBFIELD only supports Object" | ||
var markedModified; | ||
if (parts.length > 1) { | ||
for (var i = 0, len = parts.length - 1; i <= len; ++i) { | ||
if (this.isModified(parts[i])) { | ||
markedModified = true; | ||
var pathToMark | ||
, subpaths, subpath; | ||
if (parts.length <= 1) { | ||
pathToMark = path; | ||
} else { | ||
subpaths = parts.map( function (part, i) { | ||
return parts.slice(0, i).concat(part).join('.'); | ||
}); | ||
for (var i = 0, l = subpaths.length; i < l; i++) { | ||
subpath = subpaths[i]; | ||
if (this.isModified(subpath) // earlier prefixes that are already | ||
// marked as dirty have precedence | ||
|| this.get(subpath) === null) { | ||
pathToMark = subpath; | ||
break; | ||
} | ||
if (null === this.get(parts[i])) { | ||
this.activePaths.modify(parts[i]); | ||
markedModified = true; | ||
break; | ||
} | ||
} | ||
if (!pathToMark) pathToMark = path; | ||
} | ||
var markedModified = this.isModified(pathToMark); | ||
if (!markedModified) | ||
this.activePaths.modify(path); | ||
if ( (!schema || null === val || undefined === val) || | ||
@@ -264,2 +271,6 @@ this.try(function(){ | ||
){ | ||
var priorVal = this.get(path); | ||
if (!markedModified && !deepEqual(val, this.get(path))) { | ||
this.activePaths.modify(pathToMark); | ||
} | ||
for (var i = 0, l = parts.length; i < l; i++) { | ||
@@ -277,3 +288,3 @@ if (i + 1 == l) { | ||
Document.prototype._markModified = function (path) { | ||
Document.prototype.markModified = function (path) { | ||
this.activePaths.modify(path); | ||
@@ -291,11 +302,27 @@ }; | ||
var parts = path.split('.') | ||
, obj = this.doc; | ||
, obj = this.doc | ||
, part; | ||
for (var i = 0, l = parts.length; i < l-1; i++) { | ||
obj = obj[parts[i]]; | ||
part = parts[i]; | ||
path = convertIfInt(path); | ||
obj = obj.getValue | ||
? obj.getValue(part) // If we have an embedded array document member | ||
: obj[part]; | ||
if (!obj) return obj; | ||
} | ||
return obj[parts[l-1]]; | ||
part = parts[l-1]; | ||
path = convertIfInt(path); | ||
return obj.getValue | ||
? obj.getValue(part) // If we have an embedded array document member | ||
: obj[part]; | ||
}; | ||
function convertIfInt (string) { | ||
if (/^\d+$/.test(string)) { | ||
return parseInt(string, 10); | ||
} | ||
return string; | ||
} | ||
/** | ||
@@ -464,10 +491,20 @@ * Sets a raw value for a path (no casting, setters, transformations) | ||
function compile (tree, proto, prefix) { | ||
for (var i in tree) | ||
define(i, ((tree[i].constructor == Object | ||
&& Object.keys(tree[i]).length) | ||
&& (!tree[i].type || tree[i].__nested) | ||
? tree[i] | ||
var keys = Object.keys(tree) | ||
, i = keys.length | ||
, limb | ||
, key; | ||
while (i--) { | ||
key = keys[i]; | ||
limb = tree[key]; | ||
define(key | ||
, ((limb.constructor == Object | ||
&& Object.keys(limb).length) | ||
&& (!limb.type || limb.type.type) | ||
? limb | ||
: null) | ||
, proto | ||
, prefix); | ||
, proto | ||
, prefix); | ||
} | ||
}; | ||
@@ -474,0 +511,0 @@ |
@@ -10,2 +10,3 @@ | ||
, SchemaTypes = Schema.Types | ||
, SchemaDefaults = require('./schemadefault') | ||
, Types = require('./types') | ||
@@ -151,3 +152,3 @@ , Query = require('./query') | ||
// normalize collection | ||
if (!(schema instanceof Schema)){ | ||
if (!(schema instanceof Schema)) { | ||
collection = schema; | ||
@@ -157,37 +158,44 @@ schema = false; | ||
if ('boolean' === typeof collection) { | ||
skipInit = collection; | ||
collection = null; | ||
} | ||
collection = collection || utils.toCollectionName(name); | ||
// look up models for the collection | ||
if (schema){ | ||
if (!this.modelSchemas[name]) { | ||
if (!this.modelSchemas[name]) { | ||
if (name in SchemaDefaults) { | ||
schema = SchemaDefaults[name]; | ||
} | ||
if (schema) { | ||
this.modelSchemas[name] = schema; | ||
for (var i = 0, l = this.plugins.length; i < l; i++) | ||
for (var i = 0, l = this.plugins.length; i < l; i++) { | ||
schema.plugin(this.plugins[i][0], this.plugins[i][1]); | ||
} | ||
} else { | ||
throw new Error('Schema hasn\'t been registered for model "' + name + '".\n' | ||
+ 'Use mongoose.model(name, schema)'); | ||
} | ||
} else { | ||
if (!this.modelSchemas[name]) | ||
throw new Error('Schema hasn\'t been registered for model "' + name + '".\n' | ||
+ 'Use Mongoose.define(name, schema)'); | ||
} | ||
var conn = this.connection | ||
, model; | ||
var conn = this.connection | ||
, model; | ||
if (!this.models[collection]) | ||
this.models[collection] = {}; | ||
if (!this.models[collection]) this.models[collection] = {}; | ||
if (!this.models[collection][name]){ | ||
model = Model.compile(name | ||
, this.modelSchemas[name] | ||
, collection | ||
, conn | ||
, this); | ||
if (!this.models[collection][name]) { | ||
model = Model.compile(name | ||
, this.modelSchemas[name] | ||
, collection | ||
, conn | ||
, this); | ||
if (!skipInit) | ||
model.init(); | ||
if (!skipInit) model.init(); | ||
this.models[collection][name] = model; | ||
}; | ||
this.models[collection][name] = model; | ||
} | ||
return this.models[collection][name]; | ||
} | ||
return this.models[collection][name]; | ||
}; | ||
@@ -287,3 +295,3 @@ | ||
exports.version = '1.3.0'; | ||
exports.version = '1.3.1'; | ||
@@ -290,0 +298,0 @@ /** |
@@ -73,4 +73,4 @@ | ||
if (err) return promise.error(err); | ||
promise.complete(); | ||
self.emit('save'); | ||
promise.complete(self); | ||
self.emit('save', self); | ||
}; | ||
@@ -117,3 +117,9 @@ | ||
atomics = type._atomics; | ||
for (var op in atomics) { | ||
var ops = Object.keys(atomics) | ||
, i = ops.length | ||
, op; | ||
while (i--) { | ||
op = ops[i] | ||
if (op === '$pushAll' || op === '$pullAll') { | ||
@@ -135,3 +141,3 @@ if (atomics[op].length === 1) { | ||
} | ||
obj[type._path] = val.toObject | ||
obj[data.path] = val.toObject | ||
? val.toObject() // If the value is an array | ||
@@ -300,3 +306,3 @@ : Array.isArray(val) | ||
/** | ||
* Document schema | ||
* Document schema | ||
* | ||
@@ -544,2 +550,3 @@ * @api public | ||
*/ | ||
Model.create = function (doc, fn) { | ||
@@ -546,0 +553,0 @@ var args = [].slice.call(arguments) |
@@ -110,2 +110,3 @@ var utils = require('./utils') | ||
, any$conditionals, type; | ||
while (i--) { | ||
@@ -118,2 +119,3 @@ path = paths[i]; | ||
, orComponentQuery; | ||
while (k--) { | ||
@@ -163,14 +165,23 @@ orComponentQuery = new Query(val[k]) | ||
obj[path] = schematype.castForQuery(val); | ||
} else for (var $cond in val) { | ||
nested = val[$cond]; | ||
if ($cond === '$ne' && nested === null) { | ||
continue; | ||
} else if ($cond === '$exists') { | ||
if ('boolean' !== typeof nested) | ||
throw new Error("$exists parameter must be Boolean"); | ||
continue; | ||
} else if ($cond === '$not') { | ||
this.cast(model, val[$cond]); | ||
} else { | ||
val[$cond] = schematype.castForQuery($cond, nested); | ||
} else { | ||
var ks = Object.keys(val) | ||
, k = ks.length | ||
, $cond; | ||
while (k--) { | ||
$cond = ks[k]; | ||
nested = val[$cond]; | ||
if ($cond === '$ne' && nested === null) { | ||
continue; | ||
} else if ($cond === '$exists') { | ||
if ('boolean' !== typeof nested) | ||
throw new Error("$exists parameter must be Boolean"); | ||
continue; | ||
} else if ($cond === '$not') { | ||
this.cast(model, val[$cond]); | ||
} else { | ||
val[$cond] = schematype.castForQuery($cond, nested); | ||
} | ||
} | ||
@@ -523,7 +534,8 @@ } | ||
Query.prototype.sort = function () { | ||
var sort = this.options.sort || (this.options.sort = []) | ||
, args = [].slice.call(arguments); | ||
inGroupsOf(2, args, function (field, value) { | ||
var sort = this.options.sort || (this.options.sort = []); | ||
inGroupsOf(2, arguments, function (field, value) { | ||
sort.push([field, value]); | ||
}); | ||
return this; | ||
@@ -555,2 +567,36 @@ }; | ||
/** | ||
* Query hints. | ||
* | ||
* Examples: | ||
* new Query().hint({ indexA: 1, indexB: -1}) | ||
* new Query().hint("indexA", 1, "indexB", -1) | ||
* | ||
* @param {Object|String} v | ||
* @param {Int} [multi] | ||
* @return {Query} | ||
* @api public | ||
*/ | ||
Query.prototype.hint = function (v, multi) { | ||
var hint = this.options.hint || (this.options.hint = {}) | ||
, keys | ||
, i; | ||
if (multi) { | ||
inGroupsOf(2, arguments, function (field, val) { | ||
hint[field] = val; | ||
}); | ||
} else if (v.constructor === Object) { | ||
keys = Object.keys(v); | ||
i = keys.length; | ||
while (i--) { | ||
hint[keys[i]] = v[keys[i]]; | ||
} | ||
} | ||
return this; | ||
}; | ||
Query.prototype.execFind = function (callback) { | ||
@@ -557,0 +603,0 @@ var model = this.model |
@@ -120,5 +120,29 @@ | ||
Schema.prototype.path = function (path, obj) { | ||
if (obj == undefined) | ||
return this.paths[path]; | ||
if (obj == undefined) { | ||
if (this.paths[path]) return this.paths[path]; | ||
// Sometimes path will come in as | ||
// pathNameA.4.pathNameB where 4 means the index | ||
// of an embedded document in an embedded array. | ||
// In this case, we need to jump to the Array's | ||
// schema and call path() from there to resolve to | ||
// the correct path type (otherwise, it falsely | ||
// resolves to undefined | ||
var self = this | ||
, subpaths = path.split(/\.\d+\./) | ||
, val; | ||
if (subpaths.length > 1) { | ||
val = subpaths.reduce( function (val, subpath) { | ||
if (val) { | ||
return val.schema.path(subpath); | ||
} else { | ||
return self.path(subpath); | ||
} | ||
}, null); | ||
} else { | ||
return this.paths[path]; | ||
} | ||
return val; | ||
} | ||
if (obj.constructor != Object) | ||
@@ -164,5 +188,9 @@ obj = { type: obj }; | ||
Schema.prototype.eachPath = function (fn) { | ||
for (var k in this.paths) | ||
if (this.paths.hasOwnProperty(k)) | ||
fn(k, this.paths[k]); | ||
var keys = Object.keys(this.paths) | ||
, len = keys.length; | ||
for (var i = 0; i < len; ++i) { | ||
fn(keys[i], this.paths[keys[i]]); | ||
} | ||
return this; | ||
@@ -169,0 +197,0 @@ }; |
@@ -142,5 +142,9 @@ | ||
SchemaString.prototype.$conditionalHandlers = { | ||
'$ne': handleSingle | ||
, '$in': handleArray | ||
'$ne' : handleSingle | ||
, '$in' : handleArray | ||
, '$nin': handleArray | ||
, '$gt' : handleSingle | ||
, '$lt' : handleSingle | ||
, '$gte': handleSingle | ||
, '$lte': handleSingle | ||
}; | ||
@@ -147,0 +151,0 @@ SchemaString.prototype.castForQuery = function ($conditional, val) { |
@@ -69,17 +69,26 @@ | ||
/** | ||
* Marks this array as modified | ||
* Marks this array as modified. | ||
* It is called during a nonAtomicPush, an atomic opteration, | ||
* or by an existing embedded document that is modified. | ||
* | ||
* If it bubbles up from an embedded document change, | ||
* then it takes the following arguments (otherwise, takes | ||
* 0 arguments) | ||
* @param {EmbeddedDocument} embeddedDoc that invokes this method on the MongooseArray | ||
* @param {String} embeddedPath is what changed inthe embeddedDoc | ||
* | ||
* @api public | ||
*/ | ||
MongooseArray.prototype._markModified = function () { | ||
var parent = this._parent; | ||
MongooseArray.prototype._markModified = function (embeddedDoc, embeddedPath) { | ||
var parent = this._parent | ||
, dirtyPath; | ||
if (parent) { | ||
if (parent.markModified) { | ||
// If we have an embedded document | ||
parent.markModified(); | ||
} else { | ||
// If we don't have a top level document | ||
parent.activePaths.modify(this._path); | ||
dirtyPath = this._path; | ||
if (arguments.length) { | ||
// If an embedded doc bubbled up the change | ||
dirtyPath = [this._path, this.indexOf(embeddedDoc), embeddedPath].join('.'); | ||
} | ||
parent.markModified(dirtyPath); | ||
} | ||
@@ -86,0 +95,0 @@ return this; |
@@ -37,4 +37,4 @@ | ||
EmbeddedDocument.prototype.set = function () { | ||
this.markModified(); | ||
EmbeddedDocument.prototype.set = function (path) { | ||
this.markModified(path); | ||
return oldSet.apply(this, arguments); | ||
@@ -49,4 +49,10 @@ }; | ||
EmbeddedDocument.prototype.markModified = function () { | ||
this.parentArray._markModified(); | ||
EmbeddedDocument.prototype.markModified = function (path) { | ||
if (this.isNew) { | ||
// Mark the WHOLE parent array as modified | ||
// if this is a new document (i.e., we are initializing | ||
// a document), | ||
this.parentArray._markModified(); | ||
} else | ||
this.parentArray._markModified(this, path); | ||
}; | ||
@@ -53,0 +59,0 @@ |
@@ -17,3 +17,5 @@ | ||
exports.toCollectionName = function(name) { | ||
exports.toCollectionName = function (name) { | ||
if ('system.profile' === name) return name; | ||
if ('system.indexes' === name) return name; | ||
return pluralize(name.toLowerCase()); | ||
@@ -90,3 +92,3 @@ }; | ||
var rule, found; | ||
if (!~uncountables.indexOf(str.lowercase)){ | ||
if (!~uncountables.indexOf(str.toLowerCase())){ | ||
found = rules.filter(function(rule){ | ||
@@ -111,3 +113,3 @@ return str.match(rule[0]); | ||
if (!('once' in EventEmitter.prototype)){ | ||
Events = function () { | ||
@@ -122,7 +124,7 @@ EventEmitter.apply(this, arguments); | ||
Events.prototype.__proto__ = EventEmitter.prototype; | ||
/** | ||
* Add `once`. | ||
*/ | ||
Events.prototype.once = function (type, listener) { | ||
@@ -140,2 +142,41 @@ var self = this; | ||
// Modified from node/lib/assert.js | ||
exports.deepEqual = function deepEqual (a, b) { | ||
if (a === b) return true; | ||
if (a instanceof Date && b instanceof Date) | ||
return a.getTime() === b.getTime(); | ||
if (typeof a !== 'object' && typeof b !== 'object') | ||
return a == b; | ||
if (a === null || b === null || a === undefined || b === undefined) | ||
return false | ||
if (a.prototype !== b.prototype) return false; | ||
try { | ||
var ka = Object.keys(a), | ||
kb = Object.keys(b), | ||
key, i; | ||
} catch (e) {//happens when one is a string literal and the other isn't | ||
return false; | ||
} | ||
// having the same number of owned properties (keys incorporates | ||
// hasOwnProperty) | ||
if (ka.length != kb.length) | ||
return false; | ||
//the same set of keys (although not necessarily the same order), | ||
ka.sort(); | ||
kb.sort(); | ||
//~~~cheap key test | ||
for (i = ka.length - 1; i >= 0; i--) { | ||
if (ka[i] != kb[i]) | ||
return false; | ||
} | ||
//equivalent values for every corresponding key, and | ||
//~~~possibly expensive deep test | ||
for (i = ka.length - 1; i >= 0; i--) { | ||
key = ka[i]; | ||
if (!deepEqual(a[key], b[key])) return false; | ||
} | ||
return true; | ||
}; | ||
/** | ||
@@ -200,14 +241,22 @@ * Object clone with Mongoose natives support. | ||
* @param {Object} defaults | ||
* @param {Object} supplied options | ||
* @return {Object} new (merged) object | ||
* @param {Object} options | ||
* @return {Object} (merged) object | ||
* @api private | ||
*/ | ||
exports.options = function (defaults, opts){ | ||
var opts = opts || {} | ||
, c = opts; | ||
for (var i in defaults) | ||
if (!(i in opts)) | ||
c[i] = defaults[i]; | ||
return c; | ||
exports.options = function (defaults, options) { | ||
var keys = Object.keys(defaults) | ||
, i = keys.length | ||
, k ; | ||
options = options || {}; | ||
while (i--) { | ||
k = keys[i]; | ||
if (!(k in options)) { | ||
options[k] = defaults[k]; | ||
} | ||
} | ||
return options; | ||
}; | ||
@@ -214,0 +263,0 @@ |
{ | ||
"name": "mongoose" | ||
, "description": "Mongoose MongoDB ORM" | ||
, "version": "1.3.0" | ||
, "version": "1.3.1" | ||
, "author": "Guillermo Rauch <guillermo@learnboost.com>" | ||
@@ -6,0 +6,0 @@ , "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"] |
@@ -7,9 +7,6 @@ GLOBAL.DEBUG = true; | ||
var Db = require('../lib/mongodb').Db, | ||
Connection = require('../lib/mongodb').Connection, | ||
Server = require('../lib/mongodb').Server, | ||
BSON = require('../lib/mongodb').BSONPure; | ||
// BSON = require('../lib/mongodb').BSONNative; | ||
connect = require('../lib/mongodb').connect; | ||
sys.puts('Connecting to ' + (process.env.MONGO_URL || Db.DEFAULT_URL)); | ||
connect(process.env.MONGO_URL, function(err, db) { | ||
sys.puts('Connecting to ' + Db.DEFAULT_URL); | ||
connect(Db.DEFAULT_URL, function(err, db) { | ||
db.dropDatabase(function(err, result) { | ||
@@ -16,0 +13,0 @@ db.collection('test', function(err, collection) { |
@@ -88,3 +88,3 @@ var InsertCommand = require('./commands/insert_command').InsertCommand, | ||
callback = args.pop(); | ||
removeSelector = args.length ? args.shift() : {}; | ||
var removeSelector = args.length ? args.shift() : {}; | ||
options = args.length ? args.shift() : {}; | ||
@@ -351,10 +351,10 @@ | ||
* Various argument possibilities | ||
* 1 callback | ||
* 2 selector, callback, | ||
* 2 callback, options // really?! | ||
* 3 selector, fields, callback | ||
* 3 selector, options, callback | ||
* 4,selector, fields, options, callback | ||
* 5 selector, fields, skip, limit, callback | ||
* 6 selector, fields, skip, limit, timeout, callback | ||
* 1 callback? | ||
* 2 selector, callback?, | ||
* 2 callback?, options // really?! | ||
* 3 selector, fields, callback? | ||
* 3 selector, options, callback? | ||
* 4,selector, fields, options, callback? | ||
* 5 selector, fields, skip, limit, callback? | ||
* 6 selector, fields, skip, limit, timeout, callback? | ||
* | ||
@@ -366,12 +366,16 @@ * Available options: | ||
var options, | ||
len = arguments.length, | ||
selector = (len > 1) ? arguments[0] : {}, | ||
fields = (len > 2) ? arguments[1] : undefined, | ||
callback = arguments[len-1]; | ||
args = Array.prototype.slice.call(arguments, 0); | ||
has_callback = typeof args[args.length - 1] === 'function', | ||
has_weird_callback = typeof args[0] === 'function', | ||
callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null), | ||
len = args.length, | ||
selector = (len >= 1) ? args[0] : {}, | ||
fields = (len >= 2) ? args[1] : undefined; | ||
if(len == 2 && typeof arguments[0] == 'function') { | ||
selector = {}; options = arguments[1]; callback = arguments[0]; | ||
if(len == 1 && has_weird_callback) { // backwards compat for callback?, options case | ||
selector = {}; | ||
options = args[0]; | ||
} | ||
if(len == 3){ // backwards compat for options object | ||
if(len == 2){ // backwards compat for options object | ||
var test = ['limit','sort','fields','skip','hint','explain','snapshot','timeout','tailable', 'batchSize'], | ||
@@ -383,3 +387,3 @@ idx = 0, l = test.length, is_option = false; | ||
} | ||
if(len == 4) options = arguments[2]; | ||
if(len == 3) options = args[2]; | ||
@@ -390,3 +394,3 @@ if(options && options.fields){ | ||
if(options.fields.length == 0) fields['_id'] = 1; | ||
else for(i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1; | ||
else for(var i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1; | ||
} | ||
@@ -397,9 +401,15 @@ else fields = options.fields; | ||
options.skip = len > 4 ? arguments[2] : options.skip ? options.skip : 0; | ||
options.limit = len > 4 ? arguments[3] : options.limit ? options.limit : 0; | ||
options.skip = len > 3 ? args[2] : options.skip ? options.skip : 0; | ||
options.limit = len > 3 ? args[3] : options.limit ? options.limit : 0; | ||
options.hint = options.hint != null ? this.normalizeHintField(options.hint) : this.internalHint; | ||
options.timeout = len == 6 ? arguments[4] : options.timeout ? options.timeout : undefined; | ||
options.timeout = len == 5 ? args[4] : options.timeout ? options.timeout : undefined; | ||
var o = options; | ||
callback(null, new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize)); | ||
// callback for backward compatibility | ||
if (callback) { | ||
callback(null, new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize)); | ||
} else { | ||
return new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize); | ||
} | ||
}; | ||
@@ -435,3 +445,3 @@ | ||
if(options.fields.length == 0) fields['_id'] = 1; | ||
else for(i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1; | ||
else for(var i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1; | ||
} | ||
@@ -441,3 +451,3 @@ else fields = options.fields; | ||
// Unpack the options | ||
var timeout = options.timeout != null ? options.timeout : QueryCommand.OPTS_NONE; | ||
var timeout = options.timeout != null ? options.timeout : QueryCommand.OPTS_NONE; | ||
var queryOptions = timeout; | ||
@@ -510,2 +520,6 @@ // Build final query | ||
if(err == null && result.documents[0].ok == 1) { | ||
//return the results, if the map/reduce is invoked with inline option | ||
if(result.documents[0].results) { | ||
return callback(err, result.documents[0].results); | ||
} | ||
// Create a collection object that wraps the result collection | ||
@@ -512,0 +526,0 @@ self.db.collection(result.documents[0].result, function(err, collection) { |
@@ -95,12 +95,37 @@ var QueryCommand = require('./query_command').QueryCommand, | ||
var fieldHash = {}; | ||
var finalFieldOrSpec = fieldOrSpec.constructor == String ? [[fieldOrSpec, 1]] : fieldOrSpec; | ||
var indexes = []; | ||
var keys; | ||
// Get all the fields | ||
finalFieldOrSpec.forEach(function(indexArray) { | ||
var indexArrayFinal = indexArray; | ||
if(indexArrayFinal.length == 1) indexArrayFinal[1] = 1; | ||
fieldHash[indexArrayFinal[0]] = indexArrayFinal[1]; | ||
indexes.push(indexArrayFinal[0] + "_" + indexArrayFinal[1]); | ||
}); | ||
// Get all the fields accordingly | ||
if (fieldOrSpec.constructor === String) { // 'type' | ||
indexes.push(fieldOrSpec + '_' + 1); | ||
fieldHash[fieldOrSpec] = 1; | ||
} else if (fieldOrSpec.constructor === Array) { // [{location:'2d'}, ...] | ||
fieldOrSpec.forEach(function(f) { | ||
if (f.constructor === String) { // [{location:'2d'}, 'type'] | ||
indexes.push(f + '_' + 1); | ||
fieldHash[f] = 1; | ||
} else if (f.constructor === Array) { // [['location', '2d'],['type', 1]] | ||
indexes.push(f[0] + '_' + (f[1] || 1)); | ||
fieldHash[f[0]] = f[1] || 1; | ||
} else if (f.constructor === Object) { // [{location:'2d'}, {type:1}] | ||
keys = Object.keys(f); | ||
keys.forEach(function(k) { | ||
indexes.push(k + '_' + f[k]); | ||
fieldHash[k] = f[k]; | ||
}); | ||
} else { | ||
// undefined | ||
} | ||
}); | ||
} else if (fieldOrSpec.constructor === Object) { // {location:'2d', type:1} | ||
keys = Object.keys(fieldOrSpec); | ||
keys.forEach(function(key) { | ||
indexes.push(key + '_' + fieldOrSpec[key]); | ||
fieldHash[key] = fieldOrSpec[key]; | ||
}); | ||
} else { | ||
// undefined | ||
} | ||
// Generate the index name | ||
@@ -107,0 +132,0 @@ var indexName = indexes.join("_"); |
@@ -113,2 +113,6 @@ var QueryCommand = require('./commands/query_command').QueryCommand, | ||
if (!callback) { | ||
throw Error('callback is mandatory'); | ||
} | ||
try { | ||
@@ -120,11 +124,11 @@ if(this.tailable) { | ||
this.each(function(err, item) { | ||
if (item != null) { | ||
items.push(item); | ||
} else { | ||
callback(err, items); | ||
items = null; | ||
} | ||
item = null; | ||
if (item != null) { | ||
items.push(item); | ||
} else { | ||
callback(err, items); | ||
items = null; | ||
} | ||
item = null; | ||
}); | ||
@@ -159,2 +163,6 @@ } else { | ||
if (!callback) { | ||
throw Error('callback is mandatory'); | ||
} | ||
if(this.state != Cursor.CLOSED) { | ||
@@ -172,3 +180,3 @@ //FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2) | ||
} | ||
item = null; | ||
@@ -623,3 +631,3 @@ }); | ||
var command = new KillCursorCommand(this.db, [this.cursorId]); | ||
this.db.executeCommand(command, null); | ||
this.db.executeCommand(command, null); | ||
} catch(err) {} | ||
@@ -630,4 +638,10 @@ } | ||
this.state = Cursor.CLOSED; | ||
if (callback) callback(null, this); | ||
// callback for backward compatibility | ||
if (callback) { | ||
callback(null, this); | ||
} else { | ||
return this; | ||
} | ||
this.items = null; | ||
@@ -634,0 +648,0 @@ }; |
@@ -108,6 +108,23 @@ var QueryCommand = require('./commands/query_command').QueryCommand, | ||
var serverConnections = self.serverConfig instanceof ServerPair ? [self.serverConfig.leftServer, self.serverConfig.rightServer] : self.serverConfig.servers; | ||
var numberOfConnectedServers = 0; | ||
var numberOfCheckedServers = 0; | ||
serverConnections.forEach(function(server) { | ||
server.connection = new Connection(server.host, server.port, server.autoReconnect); | ||
self.connections.push(server.connection); | ||
var handleServerConnection = function() { | ||
numberOfCheckedServers+=1; | ||
if(numberOfCheckedServers == serverConnections.length) { | ||
if(self.masterConnection) { | ||
// emit a message saying we got a master and are ready to go and change state to reflect it | ||
self.state = 'connected'; | ||
callback(null, self); | ||
} else { | ||
// emit error only when all servers are checked and connecting to them failed. | ||
self.state = "notConnected" | ||
callback(new Error("Failed connecting to any of the servers in the cluster"), null); | ||
} | ||
} | ||
} | ||
@@ -118,4 +135,3 @@ server.connection.addListener("connect", function() { | ||
var connectCallback = function(err, reply) { | ||
if(err != null) { | ||
if(err != null) { | ||
callback(err, null); | ||
@@ -131,8 +147,4 @@ } else { | ||
} | ||
// emit a message saying we got a master and are ready to go and change state to reflect it | ||
if(++numberOfConnectedServers == serverConnections.length && self.state == 'notConnected') { | ||
self.state = 'connected'; | ||
callback(null, self); | ||
} | ||
handleServerConnection(); | ||
} | ||
@@ -160,8 +172,4 @@ }; | ||
server.connection.addListener("error", function(err) { | ||
if(self.listeners("error") != null && self.listeners("error").length > 0) | ||
self.state = "notConnected" | ||
return callback(err, null); | ||
}); | ||
handleServerConnection(); | ||
}); | ||
@@ -200,4 +208,10 @@ // Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event) | ||
if(collection_name != null) selector.name = this.databaseName + "." + collection_name; | ||
// Return Cursor | ||
callback(null, new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector)); | ||
// callback for backward compatibility | ||
if (callback) { | ||
callback(null, new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector)); | ||
} else { | ||
return new Cursor(this, new Collection(this, DbCommand.SYSTEM_NAMESPACE_COLLECTION), selector); | ||
} | ||
}; | ||
@@ -614,10 +628,7 @@ | ||
var db_cmnd = null; | ||
sys.puts("============================================ checkMaster_::0::" + sys.inspect(dbcopy.serverConfig.servers)) | ||
dbcopy.serverConfig.servers.forEach(function(server) { | ||
db_cmnd = DbCommand.createIsMasterCommand(dbcopy); | ||
sys.puts("============================================ checkMaster_::1") | ||
var connect_Callback = function(err, reply) { | ||
sys.puts("============================================ checkMaster_::2") | ||
if(err != null) { | ||
@@ -637,7 +648,5 @@ returnback(err, null, null) | ||
sys.puts("============================================ checkMaster_::3") | ||
dbcopy.addListener(db_cmnd.getRequestId().toString(), connect_Callback); | ||
server.connection.sendwithoutReconnect(db_cmnd); | ||
sys.puts("============================================ checkMaster_::4") | ||
server.connection.addListener("error", function(err) { | ||
@@ -647,3 +656,2 @@ dbcopy.emit("error", err); | ||
sys.puts("============================================ checkMaster_::5") | ||
// Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event) | ||
@@ -650,0 +658,0 @@ server.connection.addListener("timeout", function() { dbcopy.emit("timeout", this); }); |
{ "name" : "mongodb" | ||
, "description" : "A node.js driver for MongoDB" | ||
, "version" : "0.9.2" | ||
, "version" : "0.9.3" | ||
, "author" : "Christian Amor Kvalheim <christkv@gmail.com>" | ||
@@ -23,5 +23,5 @@ , "contributors" : [ "Nathan White <nw@nwhite.net>", | ||
, "engines" : { "node" : ">=0.4.0" } | ||
, "scripts": { "install" : "./install.sh" } | ||
, "scripts": { "install" : "bash ./install.sh" } | ||
, "licenses" : [ { "type" : "Apache License, Version 2.0" | ||
, "url" : "http://www.apache.org/licenses/LICENSE-2.0" } ] | ||
} |
@@ -19,29 +19,23 @@ Install | ||
var client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {})); | ||
client.open(function(err, p_client) { | ||
client.createCollection('test_insert', function(err, collection) { | ||
client.collection('test_insert', function(err, collection) { | ||
for(var i = 1; i < 1000; i++) { | ||
collection.insert({c:1}, function(err, docs) {}); | ||
} | ||
var client = new Db('test', new Server("127.0.0.1", 27017, {})), | ||
test = function (err, collection) { | ||
collection.insert({a:2}, function(err, docs) { | ||
collection.insert({a:2}, function(err, docs) { | ||
collection.insert({a:3}, function(err, docs) { | ||
collection.count(function(err, count) { | ||
test.assertEquals(1001, count); | ||
// Locate all the entries using find | ||
collection.find(function(err, cursor) { | ||
cursor.toArray(function(err, results) { | ||
test.assertEquals(1001, results.length); | ||
test.assertTrue(results[0] != null); | ||
collection.count(function(err, count) { | ||
test.assertEquals(1, count); | ||
}); | ||
// Let's close the db | ||
client.close(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
// Locate all the entries using find | ||
collection.find().toArray(function(err, results) { | ||
test.assertEquals(1, results.length); | ||
test.assertTrue(results.a === 2); | ||
// Let's close the db | ||
client.close(); | ||
}); | ||
}); | ||
}; | ||
client.open(function(err, p_client) { | ||
client.collection('test_insert', test); | ||
}); | ||
@@ -51,3 +45,3 @@ | ||
======== | ||
To enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below | ||
@@ -66,6 +60,6 @@ | ||
client.bson_serializer.Timestamp | ||
client.bson_serializer.DBRef | ||
client.bson_serializer.DBRef | ||
client.bson_serializer.Binary | ||
client.bson_serializer.Code | ||
GitHub information | ||
@@ -79,3 +73,3 @@ -------- | ||
$ make test | ||
$ make test | ||
@@ -89,4 +83,4 @@ in the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass. | ||
$ cd examples | ||
$ node queries.js | ||
$ cd examples | ||
$ node queries.js | ||
@@ -114,27 +108,27 @@ GridStore | ||
// Custom factory (need to provide a 12 byte array); | ||
CustomPKFactory = function() {} | ||
CustomPKFactory.prototype = new Object(); | ||
CustomPKFactory.createPk = function() { | ||
return new ObjectID("aaaaaaaaaaaa"); | ||
} | ||
// Custom factory (need to provide a 12 byte array); | ||
CustomPKFactory = function() {} | ||
CustomPKFactory.prototype = new Object(); | ||
CustomPKFactory.createPk = function() { | ||
return new ObjectID("aaaaaaaaaaaa"); | ||
} | ||
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory}); | ||
p_client.open(function(err, p_client) { | ||
p_client.dropDatabase(function(err, done) { | ||
p_client.createCollection('test_custom_key', function(err, collection) { | ||
collection.insert({'a':1}, function(err, docs) { | ||
collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { | ||
cursor.toArray(function(err, items) { | ||
test.assertEquals(1, items.length); | ||
// Let's close the db | ||
p_client.close(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
var p_client = new Db('integration_tests_20', new Server("127.0.0.1", 27017, {}), {'pk':CustomPKFactory}); | ||
p_client.open(function(err, p_client) { | ||
p_client.dropDatabase(function(err, done) { | ||
p_client.createCollection('test_custom_key', function(err, collection) { | ||
collection.insert({'a':1}, function(err, docs) { | ||
collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}, function(err, cursor) { | ||
cursor.toArray(function(err, items) { | ||
test.assertEquals(1, items.length); | ||
// Let's close the db | ||
p_client.close(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
}); | ||
Strict mode | ||
@@ -145,27 +139,22 @@ -------- | ||
that does not exist will return an Error object in the callback. Similarly if you | ||
attempt to create a collection that already exists. Strict is provided for convenience. | ||
attempt to create a collection that already exists. Strict is provided for convenience. | ||
var error_client = new Db( | ||
'integration_tests_', | ||
new Server("127.0.0.1", 27017, {auto_reconnect: false}), | ||
{strict:true}); | ||
test.assertEquals(true, error_client.strict); | ||
error_client.open(function(err, error_client) { | ||
error_client.collection('does-not-exist', function(err, collection) { | ||
test.assertTrue(err instanceof Error); | ||
test.assertEquals("Collection does-not-exist does not exist. " + | ||
"Currently in strict mode.", err.message); | ||
}); | ||
error_client.createCollection('test_strict_access_collection', | ||
function(err, collection) { | ||
error_client.collection('test_strict_access_collection', | ||
function(err, collection) { | ||
test.assertTrue(collection instanceof Collection); | ||
// Let's close the db | ||
error_client.close(); | ||
}); | ||
}); | ||
}); | ||
var error_client = new Db('integration_tests_', new Server("127.0.0.1", 27017, {auto_reconnect: false}), {strict:true}); | ||
test.assertEquals(true, error_client.strict); | ||
error_client.open(function(err, error_client) { | ||
error_client.collection('does-not-exist', function(err, collection) { | ||
test.assertTrue(err instanceof Error); | ||
test.assertEquals("Collection does-not-exist does not exist. Currently in strict mode.", err.message); | ||
}); | ||
error_client.createCollection('test_strict_access_collection', function(err, collection) { | ||
error_client.collection('test_strict_access_collection', function(err, collection) { | ||
test.assertTrue(collection instanceof Collection); | ||
// Let's close the db | ||
error_client.close(); | ||
}); | ||
}); | ||
}); | ||
Documentation | ||
@@ -192,3 +181,3 @@ ======== | ||
collection.find(query, [fields], options, function(err, cursor) {}); | ||
collection.find(query, [fields], options); | ||
@@ -233,7 +222,4 @@ cursor.nextObject(function(err, doc) {}); | ||
var collection = new mongodb.Collection(client, 'test_collection'); | ||
collection.find({}, {limit:10}, | ||
function(err, cursor) { | ||
cursor.toArray(function(err, docs) { | ||
console.dir(docs); | ||
}); | ||
collection.find({}, {limit:10}).toArray(function(err, docs) { | ||
console.dir(docs); | ||
}); | ||
@@ -240,0 +226,0 @@ }); |
@@ -8,3 +8,4 @@ | ||
, should = require('should') | ||
, mongoose = start.mongoose; | ||
, mongoose = start.mongoose | ||
, Schema = mongoose.Schema | ||
@@ -16,3 +17,3 @@ /** | ||
module.exports = { | ||
'test closing a connection that\'s already closed': function (beforeExit) { | ||
@@ -31,4 +32,18 @@ var db = mongoose.createConnection() | ||
}); | ||
}, | ||
'connection.model allows passing a schema': function () { | ||
var db = start(); | ||
var MyModel = db.model('MyModelasdf', new Schema({ | ||
name: String | ||
})); | ||
MyModel.schema.should.be.an.instanceof(Schema); | ||
MyModel.prototype.schema.should.be.an.instanceof(Schema); | ||
var m = new MyModel({name:'aaron'}); | ||
m.name.should.eql('aaron'); | ||
db.close(); | ||
} | ||
}; |
@@ -59,22 +59,17 @@ | ||
, BlogPostB = db.model('BlogPostB', collection); | ||
// query | ||
BlogPostB.find({}).should.be.an.instanceof(Query); | ||
// BlogPostB.find({}).executed.should.be.false; | ||
// query, fields | ||
BlogPostB.find({}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.find({}, {}).executed.should.be.false; | ||
// query, fields (array) | ||
BlogPostB.find({}, []).should.be.an.instanceof(Query); | ||
// BlogPostB.find({}, []).executed.should.be.false; | ||
// query, fields, options | ||
BlogPostB.find({}, {}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.find({}, {}, {}).executed.should.be.false; | ||
// query, fields (array), options | ||
BlogPostB.find({}, [], {}).should.be.an.instanceof(Query); | ||
// BlogPostB.find({}, [], {}).executed.should.be.false; | ||
@@ -87,22 +82,17 @@ db.close(); | ||
, BlogPostB = db.model('BlogPostB', collection); | ||
// query | ||
BlogPostB.findOne({}).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne({}).executed.should.be.false; | ||
// query, fields | ||
BlogPostB.findOne({}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne({}, {}).executed.should.be.false; | ||
// query, fields (array) | ||
BlogPostB.findOne({}, []).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne({}, []).executed.should.be.false; | ||
// query, fields, options | ||
BlogPostB.findOne({}, {}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne({}, {}, {}).executed.should.be.false; | ||
// query, fields (array), options | ||
BlogPostB.findOne({}, [], {}).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne({}, [], {}).executed.should.be.false; | ||
@@ -127,3 +117,2 @@ db.close(); | ||
, count = 5 | ||
// , count = 10 | ||
, q = { _id: new DocumentObjectId }; // make sure the query is fast | ||
@@ -134,22 +123,17 @@ | ||
}; | ||
// query | ||
BlogPostB.find(q, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.find(q, fn).executed.should.be.true; | ||
// query, fields | ||
BlogPostB.find(q, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.find(q, {}, fn).executed.should.be.true; | ||
// query, fields (array) | ||
BlogPostB.find(q, [], fn).should.be.an.instanceof(Query); | ||
// BlogPostB.find(q, [], fn).executed.should.be.true; | ||
// query, fields, options | ||
BlogPostB.find(q, {}, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.find(q, {}, {}, fn).executed.should.be.true; | ||
// query, fields (array), options | ||
BlogPostB.find(q, [], {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.find(q, [], {}, fn).executed.should.be.true; | ||
}, | ||
@@ -161,3 +145,2 @@ | ||
, count = 5 | ||
// , count = 10 | ||
, q = { _id: new DocumentObjectId }; // make sure the query is fast | ||
@@ -168,22 +151,17 @@ | ||
}; | ||
// query | ||
BlogPostB.findOne(q, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne(q, fn).executed.should.be.true; | ||
// query, fields | ||
BlogPostB.findOne(q, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne(q, {}, fn).executed.should.be.true; | ||
// query, fields (array) | ||
BlogPostB.findOne(q, [], fn).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne(q, [], fn).executed.should.be.true; | ||
// query, fields, options | ||
BlogPostB.findOne(q, {}, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne(q, {}, {}, fn).executed.should.be.true; | ||
// query, fields (array), options | ||
BlogPostB.findOne(q, [], {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.findOne(q, [], {}, fn).executed.should.be.true; | ||
}, | ||
@@ -196,3 +174,2 @@ | ||
BlogPostB.count({}).should.be.an.instanceof(Query); | ||
// BlogPostB.count({}).executed.should.be.false; | ||
@@ -206,3 +183,2 @@ db.close(); | ||
, count = 1; | ||
// , count = 2; | ||
@@ -214,3 +190,2 @@ function fn () { | ||
BlogPostB.count({}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.count({}, fn).executed.should.be.true; | ||
}, | ||
@@ -223,6 +198,3 @@ | ||
BlogPostB.update({}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.update({}, {}).executed.should.be.false; | ||
BlogPostB.update({}, {}, {}).should.be.an.instanceof(Query); | ||
// BlogPostB.update({}, {}, {}).executed.should.be.false; | ||
@@ -236,3 +208,2 @@ db.close(); | ||
, count = 2; | ||
// , count = 4; | ||
@@ -244,6 +215,4 @@ function fn () { | ||
BlogPostB.update({title: random()}, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.update({title: random()}, {}, fn).executed.should.be.true; | ||
BlogPostB.update({title: random()}, {}, {}, fn).should.be.an.instanceof(Query); | ||
// BlogPostB.update({title: random()}, {}, {}, fn).executed.should.be.true; | ||
}, | ||
@@ -1170,3 +1139,42 @@ | ||
}, | ||
// IDIOMATIC SYNTAX TESTS | ||
'$gt, $lt, $lte, $gte work on strings': function () { | ||
var db = start() | ||
var D = db.model('D', new Schema({dt: String}), collection); | ||
D.create({ dt: '2011-03-30' }, done); | ||
D.create({ dt: '2011-03-31' }, done); | ||
D.create({ dt: '2011-04-01' }, done); | ||
D.create({ dt: '2011-04-02' }, done); | ||
var pending = 3; | ||
function done (err) { | ||
if (err) db.close(); | ||
should.strictEqual(err, null); | ||
if (--pending) return; | ||
pending = 2; | ||
D.find({ 'dt': { $gte: '2011-03-30', $lte: '2011-04-01' }}).sort('dt', 1).run(function (err, docs) { | ||
if (--pending) db.close(); | ||
should.strictEqual(err, null); | ||
docs.length.should.eql(3); | ||
docs[0].dt.should.eql('2011-03-30'); | ||
docs[1].dt.should.eql('2011-03-31'); | ||
docs[2].dt.should.eql('2011-04-01'); | ||
docs.some(function (d) { return '2011-04-02' === d.dt }).should.be.false; | ||
}); | ||
D.find({ 'dt': { $gt: '2011-03-30', $lt: '2011-04-02' }}).sort('dt', 1).run(function (err, docs) { | ||
if (--pending) db.close(); | ||
should.strictEqual(err, null); | ||
docs.length.should.eql(2); | ||
docs[0].dt.should.eql('2011-03-31'); | ||
docs[1].dt.should.eql('2011-04-01'); | ||
docs.some(function (d) { return '2011-03-30' === d.dt }).should.be.false; | ||
docs.some(function (d) { return '2011-04-02' === d.dt }).should.be.false; | ||
}); | ||
} | ||
} | ||
}; |
@@ -551,3 +551,3 @@ | ||
// Advanced Query options | ||
'test Query#maxscan': function () { | ||
@@ -559,2 +559,22 @@ var query = new Query(); | ||
'test Query#hint': function () { | ||
var query = new Query(); | ||
query.hint('indexAttributeA', 1, 'indexAttributeB', -1); | ||
query.options.hint.should.eql({'indexAttributeA': 1, 'indexAttributeB': -1}); | ||
var query2 = new Query(); | ||
query2.hint({'indexAttributeA': 1, 'indexAttributeB': -1}); | ||
query2.options.hint.should.eql({'indexAttributeA': 1, 'indexAttributeB': -1}); | ||
var query3 = new Query(); | ||
query3.hint('indexAttributeA'); | ||
query3.options.hint.should.eql({}); | ||
}, | ||
'test Query#snapshot': function () { | ||
var query = new Query(); | ||
query.snapshot(true); | ||
query.options.snapshot.should.be.true; | ||
}, | ||
// TODO | ||
@@ -574,9 +594,2 @@ // 'test Query#min': function () { | ||
// TODO Come back to this and make better | ||
// 'test Query#hint': function () { | ||
// var query = new Query(); | ||
// query.hint('indexAttributeA', 'indexAttributeB'); | ||
// query.options.hint.should.equal('indexAttributeA', 'indexAttributeB'); | ||
// }, | ||
// TODO | ||
@@ -586,8 +599,2 @@ // 'test Query#explain': function () { | ||
'test Query#snapshot': function () { | ||
var query = new Query(); | ||
query.snapshot(true); | ||
query.options.snapshot.should.be.true; | ||
}, | ||
// 'queries should be composable': function () { | ||
@@ -594,0 +601,0 @@ // var q1 = new Query({name: 'hello'}) |
@@ -129,4 +129,27 @@ | ||
suffixedPaths.should.eql(['iAmTheWalrus-suffix', 'hello-suffix', 'world-suffix']); | ||
}, | ||
'test utils.options': function () { | ||
var o = { a: 1, b: 2, c: 3, 0: 'zero1' }; | ||
var defaults = { b: 10, d: 20, 0: 'zero2' }; | ||
var result = utils.options(defaults, o); | ||
result.a.should.equal(1); | ||
result.b.should.equal(2); | ||
result.c.should.equal(3); | ||
result.d.should.equal(20); | ||
o.d.should.equal(result.d); | ||
result['0'].should.equal('zero1'); | ||
var result2 = utils.options(defaults); | ||
result2.b.should.equal(10); | ||
result2.d.should.equal(20); | ||
result2['0'].should.equal('zero2'); | ||
// same properties/vals | ||
defaults.should.eql(result2); | ||
// same object | ||
defaults.should.not.equal(result2); | ||
} | ||
}; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
3134939
214
27019
77
16