Comparing version 1.8.1 to 1.8.2
1.8.2 / 2011-08-17 | ||
=================== | ||
* fixed; reset connection.readyState after failure [tomseago] | ||
* fixed; can now query positionally for non-embedded docs (arrays of numbers/strings etc) | ||
* fixed; embedded document query casting | ||
* added; support for passing options to node-mongo-native db, server, and replsetserver [tomseago] | ||
1.8.1 / 2011-08-10 | ||
@@ -3,0 +11,0 @@ =================== |
@@ -48,4 +48,2 @@ | ||
* A hash of the collections associated with this connection | ||
* | ||
* @param text | ||
*/ | ||
@@ -66,41 +64,79 @@ | ||
* | ||
* `options` is a hash with the following optional properties: | ||
* | ||
* options.db - passed to the connection db instance | ||
* options.server - passed to the connection server instance(s) | ||
* options.replset - passed to the connection ReplSetServer instance | ||
* | ||
* Notes: | ||
* | ||
* Mongoose forces the db option `forceServerObjectId` false and cannot | ||
* be overridden. | ||
* | ||
* Mongoose defaults the server `auto_reconnect` option to false for now. | ||
* | ||
* See the node-mongodb-native driver instance for options that it | ||
* understands. | ||
* | ||
* @param {String} mongodb://uri | ||
* @return {Connection} self | ||
* @see https://github.com/christkv/node-mongodb-native | ||
* @api public | ||
*/ | ||
Connection.prototype.open = function (host, database, port, callback) { | ||
Connection.prototype.open = function (host, database, port, options, callback) { | ||
var self = this | ||
, uri; | ||
// if we've been supplied an uri | ||
if (typeof database != 'string'){ | ||
if ('string' === typeof database) { | ||
switch (arguments.length) { | ||
case 3: | ||
switch (typeof port) { | ||
case 'function': | ||
callback = port, port = 27017, options = {}; | ||
break; | ||
case 'number': | ||
options = {}; | ||
break; | ||
case 'object': | ||
options = port, port = 27017; | ||
break; | ||
} | ||
break; | ||
case 4: | ||
if ('function' === typeof options) | ||
callback = options, options = {}; | ||
} | ||
} else { | ||
switch (typeof database) { | ||
case 'function': | ||
callback = database, options = {}; | ||
break; | ||
case 'object': | ||
options = database; | ||
callback = port; | ||
break; | ||
case 'undefined': | ||
options = {}; | ||
} | ||
uri = url.parse(host); | ||
host = uri.hostname; | ||
port = uri.port || 27017; | ||
callback = database; | ||
database = uri.pathname.replace(/\//g, ''); | ||
} else { | ||
callback = callback || port; | ||
port = typeof port == 'number' ? port : 27017; | ||
database = uri.pathname && uri.pathname.replace(/\//g, ''); | ||
} | ||
callback = callback || noop; | ||
this.options = this.defaultOptions(options); | ||
// make sure we can open | ||
if (this.readyState != 0){ | ||
if ('function' == typeof callback) | ||
callback(new Error('Trying to open unclosed connection')); | ||
if (0 !== this.readyState) { | ||
var err = new Error('Trying to open unclosed connection.'); | ||
err.state = this.readyState; | ||
callback(err); | ||
return this; | ||
} | ||
// handle authentication | ||
if (uri && uri.auth){ | ||
var auth = uri.auth.split(':'); | ||
this.user = auth[0]; | ||
this.pass = auth[1]; | ||
} else | ||
this.user = this.pass = undefined; | ||
if (!host) { | ||
if ('function' == typeof callback) | ||
callback(new Error('Please provide a valid hostname.')); | ||
callback(new Error('Missing connection hostname.')); | ||
return this; | ||
@@ -110,7 +146,15 @@ } | ||
if (!database) { | ||
if ('function' == typeof callback) | ||
callback(new Error('Please provide a database to connect to.')); | ||
callback(new Error('Missing connection database.')); | ||
return this; | ||
} | ||
// handle authentication | ||
if (uri && uri.auth) { | ||
var auth = uri.auth.split(':'); | ||
this.user = auth[0]; | ||
this.pass = auth[1]; | ||
} else { | ||
this.user = this.pass = undefined; | ||
} | ||
this.name = database; | ||
@@ -127,10 +171,8 @@ this.host = host; | ||
if (err) { | ||
if (typeof callback == 'function') | ||
callback(err); | ||
self.readyState = 0; | ||
} else { | ||
self.onOpen(); | ||
} | ||
if (typeof callback == 'function') | ||
callback(null); | ||
} | ||
callback(err || null); | ||
}); | ||
@@ -147,27 +189,44 @@ | ||
* | ||
* The options parameter is passed to the low level connection. See the | ||
* node-mongodb-native driver instance for detail. | ||
* | ||
* @param {String} comma-separated mongodb:// URIs | ||
* @param {String} optional database name | ||
* @param {Object} optional options | ||
* @param {Function} optional callback | ||
*/ | ||
Connection.prototype.openSet = function (uris, database, callback) { | ||
Connection.prototype.openSet = function (uris, database, options, callback) { | ||
var uris = uris.split(',') | ||
, self = this; | ||
switch (arguments.length) { | ||
case 3: | ||
this.name = database; | ||
if ('function' === typeof options) callback = options, options = {}; | ||
break; | ||
case 2: | ||
switch (typeof database) { | ||
case 'string': | ||
this.name = database; | ||
case 'function': | ||
callback = database, database = null; | ||
break; | ||
case 'object': | ||
options = database, database = null; | ||
break; | ||
} | ||
} | ||
this.options = options = this.defaultOptions(options); | ||
callback = callback || noop; | ||
if (uris.length < 2) { | ||
if (callback) callback(new Error('Please provide comma-separated URIs')); | ||
callback(new Error('Please provide comma-separated URIs')); | ||
return this; | ||
} | ||
// signal connecting | ||
this.readyState = 2; | ||
this.emit('opening'); | ||
this.host = []; | ||
this.port = []; | ||
if ('function' == typeof database) | ||
callback = database; | ||
else | ||
this.name = database; | ||
uris.forEach(function (uri) { | ||
@@ -190,18 +249,18 @@ var uri = url.parse(uri); | ||
if (!this.name) { | ||
if (callback) | ||
callback(new Error('No database name provided for replica set')); | ||
return; | ||
callback(new Error('No database name provided for replica set')); | ||
return this; | ||
} | ||
this.readyState = 2; | ||
this.emit('opening'); | ||
// open connection | ||
this.doOpenSet(function (err) { | ||
if (err) { | ||
if (typeof callback == 'function') | ||
callback(err); | ||
self.readyState = 0; | ||
} else { | ||
self.onOpen(); | ||
} | ||
if (typeof callback == 'function') | ||
callback(null); | ||
} | ||
callback(err || null); | ||
}); | ||
@@ -218,3 +277,3 @@ }; | ||
var self = this; | ||
function open () { | ||
@@ -227,10 +286,10 @@ self.readyState = 1; | ||
self.collections[i].onOpen(); | ||
self.emit('open'); | ||
}; | ||
// re-authenticate | ||
if (self.user && self.pass) | ||
self.db.authenticate(self.user, self.pass, open); | ||
else | ||
else | ||
open(); | ||
@@ -256,3 +315,3 @@ }; | ||
case 1: // connected | ||
case 1: // connected | ||
this.readyState = 3; | ||
@@ -293,3 +352,3 @@ this.doClose(function(err){ | ||
this.readyState = 0; | ||
// avoid having the collection subscribe to our event emitter | ||
@@ -416,2 +475,30 @@ // to prevent 0.3 warning | ||
/** | ||
* Prepares default connection options. | ||
* | ||
* @param {Object} options | ||
* @api private | ||
*/ | ||
Connection.prototype.defaultOptions = function (options) { | ||
var o = options || {}; | ||
o.server = o.server || {}; | ||
if (!('auto_reconnect' in o.server)) { | ||
o.server.auto_reconnect = false; | ||
} | ||
o.db = o.db || {}; | ||
o.db.forceServerObjectId = false; | ||
return o; | ||
} | ||
/** | ||
* Noop. | ||
*/ | ||
function noop () {} | ||
/** | ||
* Module exports. | ||
@@ -418,0 +505,0 @@ */ |
@@ -27,4 +27,13 @@ /** | ||
/** | ||
* Opens the connection | ||
* | ||
* Opens the connection. | ||
* | ||
* Example server options: | ||
* auto_reconnect (default: false) | ||
* poolSize (default: 1) | ||
* | ||
* Example db options: | ||
* pk - custom primary key factory to generate `_id` values | ||
* | ||
* Some of these may break Mongoose. Use at your own risk. You have been warned. | ||
* | ||
* @param {Function} callback | ||
@@ -35,5 +44,9 @@ * @api private | ||
NativeConnection.prototype.doOpen = function (fn) { | ||
if (!this.db) | ||
this.db = new mongo.Db(this.name, new mongo.Server(this.host, this.port)); | ||
var server; | ||
if (!this.db) { | ||
server = new mongo.Server(this.host, this.port, this.options.server); | ||
this.db = new mongo.Db(this.name, server, this.options.db); | ||
} | ||
this.db.open(fn); | ||
@@ -47,3 +60,11 @@ | ||
* | ||
* @param {Function} callback | ||
* See description of doOpen for server options. In this case options.replset | ||
* is also passed to ReplSetServers. Some additional options there are | ||
* | ||
* reconnectWait (default: 1000) | ||
* retries (default: 30) | ||
* rs_name (default: false) | ||
* read_secondary (default: false) Are reads allowed from secondaries? | ||
* | ||
* @param {Function} fn | ||
* @api private | ||
@@ -58,6 +79,7 @@ */ | ||
this.host.forEach(function (host, i) { | ||
servers.push(new mongo.Server(host, ports[i], {})); | ||
servers.push(new mongo.Server(host, ports[i], this.options.server)); | ||
}); | ||
this.db = new mongo.Db(this.name, new ReplSetServers(servers, {})); | ||
var server = new ReplSetServers(servers, this.options.replset); | ||
this.db = new mongo.Db(this.name, server, this.options.db); | ||
} | ||
@@ -70,3 +92,2 @@ | ||
/** | ||
@@ -73,0 +94,0 @@ * Closes the connection |
@@ -292,3 +292,3 @@ | ||
exports.version = '1.8.1'; | ||
exports.version = '1.8.2'; | ||
@@ -295,0 +295,0 @@ /** |
@@ -173,3 +173,3 @@ var utils = require('./utils') | ||
// Apply the casting; similar code for $elemMatch in schema/array.js | ||
if (schematype.caster) { | ||
if (schematype.caster && schematype.caster.schema) { | ||
remainingConds = {}; | ||
@@ -176,0 +176,0 @@ pathLastHalf = split.slice(j).join('.'); |
@@ -132,10 +132,3 @@ /** | ||
, '$ne': function (val) { | ||
if (Array.isArray(val)) { | ||
return this.cast(val); | ||
} else { | ||
var proto = this.caster.prototype; | ||
var method = proto.castForQuery || proto.cast; | ||
if (method) return method.call(proto, val); | ||
return val != null && val.toObject ? val.toObject() : val; | ||
} | ||
return this.castForQuery(val); | ||
} | ||
@@ -162,3 +155,3 @@ , '$in': function (val) { | ||
throw new Error("Can't use " + $conditional + " with Array."); | ||
return handler.call(this, val); | ||
val = handler.call(this, val); | ||
} else { | ||
@@ -168,3 +161,2 @@ val = $conditional; | ||
val = this.cast(val); | ||
return val.toObject ? val.toObject() : val; | ||
} else { | ||
@@ -174,5 +166,5 @@ var proto = this.caster.prototype; | ||
if (method) val = method.call(proto, val); | ||
return val.toObject ? val.toObject() : val; | ||
} | ||
} | ||
return val && val.toObject ? val.toObject() : val; | ||
}; | ||
@@ -179,0 +171,0 @@ |
@@ -26,14 +26,9 @@ | ||
// make sure these internal props don't show up in Object.keys() | ||
Object.defineProperties(arr, { | ||
_atomics: { value: {} } | ||
, validators: { value: [] } | ||
, _path: { value: path } | ||
, _parent: { value: doc } | ||
}); | ||
arr._atomics = {}; | ||
arr.validators = []; | ||
arr._path = path; | ||
arr._parent = doc; | ||
if (doc) { | ||
Object.defineProperty(arr, '_schema', { | ||
value: doc.schema.path(path) | ||
}); | ||
arr._schema = doc.schema.path(path); | ||
} | ||
@@ -40,0 +35,0 @@ |
{ | ||
"name": "mongoose" | ||
, "description": "Mongoose MongoDB ORM" | ||
, "version": "1.8.1" | ||
, "version": "1.8.2" | ||
, "author": "Guillermo Rauch <guillermo@learnboost.com>" | ||
@@ -6,0 +6,0 @@ , "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"] |
@@ -104,5 +104,6 @@ | ||
module.exports = function(){ | ||
module.exports = function (options) { | ||
return mongoose.createConnection( | ||
process.env.MONGOOSE_TEST_URI || 'mongodb://localhost/mongoose_test' | ||
process.env.MONGOOSE_TEST_URI || 'mongodb://localhost/mongoose_test' | ||
, options | ||
); | ||
@@ -109,0 +110,0 @@ }; |
@@ -32,2 +32,201 @@ | ||
'test connection args': function (beforeExit) { | ||
var db = mongoose.createConnection('mongodb://localhost/fake'); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
should.strictEqual(undefined, db.pass); | ||
should.strictEqual(undefined, db.user); | ||
db.name.should.equal('fake'); | ||
db.host.should.equal('localhost'); | ||
db.port.should.equal(27017); | ||
db.close(); | ||
db = mongoose.createConnection('mongodb://localhost:27000/fake'); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
should.strictEqual(undefined, db.pass); | ||
should.strictEqual(undefined, db.user); | ||
db.name.should.equal('fake'); | ||
db.host.should.equal('localhost'); | ||
db.port.should.equal('27000'); | ||
db.close(); | ||
db = mongoose.createConnection('mongodb://aaron:psw@localhost:27000/fake'); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
should.strictEqual('psw', db.pass); | ||
should.strictEqual('aaron', db.user); | ||
db.name.should.equal('fake'); | ||
db.host.should.equal('localhost'); | ||
db.port.should.equal('27000'); | ||
db.close(); | ||
db = mongoose.createConnection('mongodb://aaron:psw@localhost:27000/fake', { db: { forceServerObjectId: true }}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.close(); | ||
db = mongoose.createConnection('mongodb://aaron:psw@localhost:27000/fake', { server: { auto_reconnect: true }}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.true; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.close(); | ||
var called1 = false; | ||
db = mongoose.createConnection('mongodb://aaron:psw@localhost:27000/fake', { server: { auto_reconnect: true }}, function () { | ||
called1 = true; | ||
}); | ||
beforeExit(function () { | ||
called1.should.be.true; | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.true; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.close(); | ||
var called2 = false; | ||
db = mongoose.createConnection('mongodb://localhost/fake', function () { | ||
called2 = true; | ||
}); | ||
beforeExit(function () { | ||
called2.should.be.true; | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('fake'); | ||
db.host.should.equal('localhost'); | ||
db.port.should.equal(27017); | ||
db.close(); | ||
db = mongoose.createConnection('mongodb:///fake', function (err) { | ||
err.message.should.equal('Missing connection hostname.'); | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
should.strictEqual(undefined, db.name); | ||
should.strictEqual(undefined, db.host); | ||
should.strictEqual(undefined, db.port); | ||
db.close(); | ||
db = mongoose.createConnection('mongodb://localhost', function (err) { | ||
err.message.should.equal('Missing connection database.'); | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
should.strictEqual(undefined, db.name); | ||
should.strictEqual(undefined, db.host); | ||
should.strictEqual(undefined, db.port); | ||
db.close(); | ||
var called3 = false; | ||
db = mongoose.createConnection('127.0.0.1', 'faker', 28000, { server: { auto_reconnect: true }}, function () { | ||
called3 = true; | ||
}); | ||
beforeExit(function () { | ||
called3.should.be.true; | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.true; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(28000); | ||
db.close(); | ||
var called4 = false; | ||
db = mongoose.createConnection('127.0.0.1', 'faker', 28000, function () { | ||
called4 = true; | ||
}); | ||
beforeExit(function () { | ||
called4.should.be.true; | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(28000); | ||
db.close(); | ||
db = mongoose.createConnection('127.0.0.1', 'faker', 28000, { server: { auto_reconnect: true }}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.true; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(28000); | ||
db.close(); | ||
db = mongoose.createConnection('127.0.0.1', 'faker', 28001); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(28001); | ||
db.close(); | ||
db = mongoose.createConnection('127.0.0.1', 'faker', { blah: 1 }); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.options.blah.should.equal(1); | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(27017); | ||
db.close(); | ||
var called5 = false | ||
db = mongoose.createConnection('127.0.0.1', 'faker', function () { | ||
called5 = true; | ||
}); | ||
beforeExit(function () { | ||
called5.should.be.true; | ||
}); | ||
db.options.should.be.a('object'); | ||
db.options.server.should.be.a('object'); | ||
db.options.server.auto_reconnect.should.be.false; | ||
db.options.db.should.be.a('object'); | ||
db.options.db.forceServerObjectId.should.be.false; | ||
db.name.should.equal('faker'); | ||
db.host.should.equal('127.0.0.1'); | ||
db.port.should.equal(27017); | ||
db.close(); | ||
}, | ||
'connection.model allows passing a schema': function () { | ||
@@ -34,0 +233,0 @@ var db = start(); |
@@ -820,3 +820,2 @@ | ||
// TODO Won't pass until we fix materialization/raw data assymetry | ||
'test find where $exists': function () { | ||
@@ -870,3 +869,3 @@ var db = start() | ||
BlogPostB.create({comments: [{title: 'i should be queryable'}]}, function (err, created) { | ||
BlogPostB.create({comments: [{title: 'i should be queryable'}], numbers: [1,2,33333], tags:['yes', 'no']}, function (err, created) { | ||
should.strictEqual(err, null); | ||
@@ -876,3 +875,19 @@ BlogPostB.findOne({'comments.title': 'i should be queryable'}, function (err, found) { | ||
found._id.should.eql(created._id); | ||
db.close(); | ||
BlogPostB.findOne({'comments.0.title': 'i should be queryable'}, function (err, found) { | ||
should.strictEqual(err, null); | ||
found._id.should.eql(created._id); | ||
// GH-463 | ||
BlogPostB.findOne({'numbers.2': 33333}, function (err, found) { | ||
should.strictEqual(err, null); | ||
found._id.should.eql(created._id); | ||
BlogPostB.findOne({'tags.1': 'no'}, function (err, found) { | ||
should.strictEqual(err, null); | ||
found._id.should.eql(created._id); | ||
db.close(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -879,0 +894,0 @@ }); |
@@ -624,3 +624,3 @@ | ||
params.comments.$ne.should.be.instanceof(Array); | ||
params.comments.$ne[0].toObject().should.eql(castedComment); | ||
params.comments.$ne[0].should.eql(castedComment); | ||
params.strings.$ne.should.be.instanceof(Array); | ||
@@ -627,0 +627,0 @@ params.strings.$ne[0].should.eql('Hi there'); |
@@ -60,3 +60,3 @@ | ||
'object'.should.eql(typeof b); | ||
Object.keys(b).length.should.equal(4); | ||
Object.keys(b.toObject()).length.should.equal(4); | ||
}, | ||
@@ -63,0 +63,0 @@ |
Sorry, the diff of this file is too big to display
758361
119
15068