Added node-modules

This commit is contained in:
Dobie Wollert
2014-09-14 07:04:16 -04:00
parent 663941bf57
commit 6a92348cf5
4870 changed files with 670395 additions and 0 deletions

13
node_modules/mongoose/.npmignore generated vendored Normal file
View File

@ -0,0 +1,13 @@
lib-cov
**.swp
*.sw*
*.orig
.DS_Store
node_modules/
benchmarks/
docs/
test/
Makefile
CNAME
index.html
index.jade

7
node_modules/mongoose/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,7 @@
language: node_js
node_js:
- 0.6
- 0.8
- 0.10
services:
- mongodb

60
node_modules/mongoose/CONTRIBUTING.md generated vendored Normal file
View File

@ -0,0 +1,60 @@
## Contributing to Mongoose
### STOP!
If you have a question about Mongoose (not a bug report) please post it to either [StackOverflow](http://stackoverflow.com/questions/tagged/mongoose), our [Google Group](http://groups.google.com/group/mongoose-orm), or on the #mongoosejs irc channel on freenode.
### Reporting bugs
- Before opening a new issue, look for existing [issues](https://github.com/learnboost/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/learnboost/mongoose/issues/new).
- Please describe the issue you are experiencing, along with any associated stack trace.
- Please post code that reproduces the issue, the version of mongoose, node version, and mongodb version.
- _The source of this project is written in javascript, not coffeescript, therefore your bug reports should be written in javascript_.
- In general, adding a "+1" comment to an existing issue does little to help get it resolved. A better way is to submit a well documented pull request with clean code and passing tests.
### Requesting new features
- Before opening a new issue, look for existing [issues](https://github.com/learnboost/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/learnboost/mongoose/issues/new).
- Please describe a use case for it
- it would be ideal to include test cases as well
- In general, adding a "+1" comment to an existing issue does little to help get it resolved. A better way is to submit a well documented pull request with clean code and passing tests.
### Fixing bugs / Adding features
- Before starting to write code, look for existing [issues](https://github.com/learnboost/mongoose/issues). That way you avoid working on something that might not be of interest or that has been addressed already in a different branch. You can create a new issue [here](https://github.com/learnboost/mongoose/issues/new).
- _The source of this project is written in javascript, not coffeescript, therefore your bug reports should be written in javascript_.
- Fork the [repo](https://github.com/learnboost/mongoose) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
- Follow the general coding style of the rest of the project:
- 2 space tabs
- no trailing whitespace
- comma first
- inline documentation for new methods, class members, etc
- 1 space between conditionals/functions, and their parenthesis and curly braces
- `if (..) {`
- `for (..) {`
- `while (..) {`
- `function (err) {`
- Write tests and make sure they pass (tests are in the [test](https://github.com/LearnBoost/mongoose/tree/master/test) directory).
### Running the tests
- Open a terminal and navigate to the root of the project
- execute `npm install` to install the necessary dependencies
- execute `make test` to run the tests (we're using [mocha](http://visionmedia.github.com/mocha/))
- or to execute a single test `T="-g 'some regexp that matches the test description'" make test`
- any mocha flags can be specified with T="..."
### Documentation
To contribute to the [API documentation](http://mongoosejs.com/docs/api.html) just make your changes to the inline documentation of the appropriate [source code](https://github.com/LearnBoost/mongoose/tree/master/lib) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.jade` files in the [docs](https://github.com/LearnBoost/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here.
If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make docs` from the project root, which switches to the gh-pages branch, merges from master, and builds all the static pages for you. Now execute `node server.js` from the project root which will launch a local webserver where you can browse the documentation site locally. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes.
### Plugins website
The [plugins](http://plugins.mongoosejs.com/) site is also an [open source project](https://github.com/aheckmann/mongooseplugins) that you can get involved with. Feel free to fork and improve it as well!
### Sharing your projects
All are welcome to share their creations which use mongoose on our [tumbler](http://mongoosejs.tumblr.com/). Just fill out the [simple submission form](http://mongoosejs.tumblr.com/submit).

1673
node_modules/mongoose/History.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

269
node_modules/mongoose/README.md generated vendored Normal file
View File

@ -0,0 +1,269 @@
## What's Mongoose?
Mongoose is a [MongoDB](http://www.mongodb.org/) object modeling tool designed to work in an asynchronous environment.
## Documentation
[mongoosejs.com](http://mongoosejs.com/)
## Try it live
<a href="https://runnable.com/#learnboost/mongoose/code.js/launch" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
## Support
- [Stack Overflow](http://stackoverflow.com/questions/tagged/mongoose)
- [bug reports](https://github.com/learnboost/mongoose/issues/)
- [help forum](http://groups.google.com/group/mongoose-orm)
- [10gen support](http://www.mongodb.org/display/DOCS/Technical+Support)
- (irc) #mongoosejs on freenode
## Installation
First install [node.js](http://nodejs.org/) and [mongodb](http://www.mongodb.org/downloads).
$ npm install mongoose
## Plugins
Check out the [plugins search site](http://plugins.mongoosejs.com/) to see hundreds of related modules from the community.
## Contributors
View all 90+ [contributors](https://github.com/learnboost/mongoose/graphs/contributors).
## Get Involved
Stand up and be counted as a [contributor](https://github.com/LearnBoost/mongoose/blob/master/CONTRIBUTING.md) too!
## Overview
### Connecting to MongoDB
First, we need to define a connection. If your app uses only one database, you should use `mongose.connect`. If you need to create additional connections, use `mongoose.createConnection`.
Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters `host, database, port, options`.
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_database');
Once connected, the `open` event is fired on the `Connection` instance. If you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. Otherwise, `mongoose.createConnection` return value is a `Connection`.
**Important!** Mongoose buffers all the commands until it's connected to the database. This means that you don't have to wait until it connects to MongoDB in order to define models, run queries, etc.
### Defining a Model
Models are defined through the `Schema` interface.
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
});
Aside from defining the structure of your documents and the types of data you're storing, a Schema handles the definition of:
* [Validators](http://mongoosejs.com/docs/validation.html) (async and sync)
* [Defaults](http://mongoosejs.com/docs/api.html#schematype_SchemaType-default)
* [Getters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-get)
* [Setters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set)
* [Indexes](http://mongoosejs.com/docs/guide.html#indexes)
* [Middleware](http://mongoosejs.com/docs/middleware.html)
* [Methods](http://mongoosejs.com/docs/guide.html#methods) definition
* [Statics](http://mongoosejs.com/docs/guide.html#statics) definition
* [Plugins](http://mongoosejs.com/docs/plugins.html)
* [pseudo-JOINs](http://mongoosejs.com/docs/populate.html)
The following example shows some of these features:
var Comment = new Schema({
name : { type: String, default: 'hahaha' }
, age : { type: Number, min: 18, index: true }
, bio : { type: String, match: /[a-z]/ }
, date : { type: Date, default: Date.now }
, buff : Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we can access it through the same function
var myModel = mongoose.model('ModelName');
Or just do it all at once
var MyModel = mongoose.model('ModelName', mySchema);
We can then instantiate it, and save it:
var instance = new MyModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
Or we can find documents from the same collection
MyModel.find({}, function (err, docs) {
// docs.forEach
});
You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html).
**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this case access your model through the connection you created:
var conn = mongoose.createConnection('your connection string');
var MyModel = conn.model('ModelName', schema);
var m = new MyModel;
m.save() // works
vs
var conn = mongoose.createConnection('your connection string');
var MyModel = mongoose.model('ModelName', schema);
var m = new MyModel;
m.save() // does not work b/c the default connection object was never connected
### Embedded Documents
In the first example snippet, we defined a key in the Schema that looks like:
comments: [Comments]
Where `Comments` is a `Schema` we created. This means that creating embedded documents is as simple as:
// retrieve my model
var BlogPost = mongoose.model('BlogPost');
// create a blog post
var post = new BlogPost();
// create a comment
post.comments.push({ title: 'My comment' });
post.save(function (err) {
if (!err) console.log('Success!');
});
The same goes for removing them:
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
Embedded documents enjoy all the same features as your models. Defaults, validators, middleware. Whenever an error occurs, it's bubbled to the `save()` error callback, so error handling is a snap!
Mongoose interacts with your embedded documents in arrays _atomically_, out of the box.
### Middleware
See the [docs](http://mongoosejs.com/docs/middleware.html) page.
#### Intercepting and mutating method arguments
You can intercept method arguments via middleware.
For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to a new value:
schema.pre('set', function (next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments. To do so, just pass the new values to `next`:
.pre(method, function firstPre (next, methodArg1, methodArg2) {
// Mutate methodArg1
next("altered-" + methodArg1.toString(), methodArg2);
})
// pre declaration is chainable
.pre(method, function secondPre (next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
console.log(methodArg2);
// => 'originalValOfMethodArg2'
// Passing no arguments to `next` automatically passes along the current argument values
// i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)`
// and also equivalent to, with the example method arg
// values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')`
next();
})
#### Schema gotcha
`type`, when used in a schema has special meaning within Mongoose. If your schema requires using `type` as a nested property you must use object notation:
new Schema({
broken: { type: Boolean }
, asset : {
name: String
, type: String // uh oh, it broke. asset will be interpreted as String
}
});
new Schema({
works: { type: Boolean }
, asset : {
name: String
, type: { type: String } // works. asset is an object with a type property
}
});
### Driver access
The driver being used defaults to [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) and is directly accessible through `YourModel.collection`. **Note**: using the driver directly bypasses all Mongoose power-tools like validation, getters, setters, hooks, etc.
## API Docs
Find the API docs [here](http://mongoosejs.com/docs/api.html), generated by [dox](http://github.com/visionmedia/dox).
## License
Copyright (c) 2010 LearnBoost &lt;dev@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

42
node_modules/mongoose/examples/README.md generated vendored Normal file
View File

@ -0,0 +1,42 @@
This directory contains runnable sample mongoose programs.
To run:
- first install [Node.js](http://nodejs.org/)
- from the command line, execute: `node example.js`, replacing "example.js" with the name of a program.
Goal is to show:
- global schemas
- GeoJSON schemas / use (with crs)
- text search
- storing schemas as json
- lean querires
- statics
- methods and statics on subdocs
- custom types
- querybuilder
- promises
- express + mongoose
- accessing driver collection, db
- connecting to replica sets
- connecting to sharded clusters
- enabling a fail fast mode
- on the fly schemas
- storing files
- map reduce
- aggregation
- advanced hooks
- using $elemMatch to return a subset of an array
- query casting
- upserts
- pagination
- express + mongoose session handling
- group by (use aggregation)
- authentication
- schema migration techniques
- converting documents to plain objects (show transforms)
- how to $unset

70
node_modules/mongoose/examples/doc-methods.js generated vendored Normal file
View File

@ -0,0 +1,70 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Schema
*/
var CharacterSchema = Schema({
name: { type: String, required: true }
, health: { type: Number, min: 0, max: 100 }
})
/**
* Methods
*/
CharacterSchema.methods.attack = function () {
console.log('%s is attacking', this.name);
}
/**
* Character model
*/
var Character = mongoose.model('Character', CharacterSchema);
/**
* Connect to the database on localhost with
* the default port (27017)
*/
var dbname = 'mongoose-example-doc-methods-' + ((Math.random()*10000)|0);
var uri = 'mongodb://localhost/' + dbname;
console.log('connecting to %s', uri);
mongoose.connect(uri, function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
example();
})
/**
* Use case
*/
function example () {
Character.create({ name: 'Link', health: 100 }, function (err, link) {
if (err) return done(err);
console.log('found', link);
link.attack(); // 'Link is attacking'
done();
})
}
/**
* Clean up
*/
function done (err) {
if (err) console.error(err);
mongoose.connection.db.dropDatabase(function () {
mongoose.disconnect();
})
}

42
node_modules/mongoose/examples/hooks.js generated vendored Normal file
View File

@ -0,0 +1,42 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
mongoose.connect('mongodb://localhost/example-hooks');
var schema = Schema({ name: String });
schema.post('save', function () {
console.log('post save hook', arguments);
})
schema.pre('save', function (next) {
console.log('pre save');
next();
})
var M = mongoose.model('Hooks', schema);
var doc = new M({ name: 'hooooks' });
doc.save(function (err) {
console.log('save callback');
mongoose.disconnect();
})
////
Model.on('init', cb);
Model.on('remove', cb);
Model.on('update', cb);
// Model.update() and doc.save()
Model.on('insert', cb);
Model.on('save', cb);
var promise = Model.save(doc, options, callback);
//
var schema = new Schema(..);
schema.pre('save', function (next, done) {
})

View File

@ -0,0 +1,135 @@
var assert = require('assert')
var mongoose = require('../');
var Schema = mongoose.Schema;
var ObjectId = mongoose.Types.ObjectId;
/**
* Connect to the db
*/
var dbname = 'testing_populateAdInfinitum_' + require('../lib/utils').random()
mongoose.connect('localhost', dbname);
mongoose.connection.on('error', function() {
console.error('connection error', arguments);
});
/**
* Schemas
*/
var user = new Schema({
name: String,
friends: [{
type: Schema.ObjectId,
ref: 'User'
}]
});
var User = mongoose.model('User', user);
var blogpost = Schema({
title: String,
tags: [String],
author: {
type: Schema.ObjectId,
ref: 'User'
}
})
var BlogPost = mongoose.model('BlogPost', blogpost);
/**
* example
*/
mongoose.connection.on('open', function() {
/**
* Generate data
*/
var userIds = [new ObjectId, new ObjectId, new ObjectId, new ObjectId];
var users = [];
users.push({
_id: userIds[0],
name: 'mary',
friends: [userIds[1], userIds[2], userIds[3]]
});
users.push({
_id: userIds[1],
name: 'bob',
friends: [userIds[0], userIds[2], userIds[3]]
});
users.push({
_id: userIds[2],
name: 'joe',
friends: [userIds[0], userIds[1], userIds[3]]
});
users.push({
_id: userIds[3],
name: 'sally',
friends: [userIds[0], userIds[1], userIds[2]]
});
User.create(users, function(err, docs) {
assert.ifError(err);
var blogposts = [];
blogposts.push({
title: 'blog 1',
tags: ['fun', 'cool'],
author: userIds[3]
})
blogposts.push({
title: 'blog 2',
tags: ['cool'],
author: userIds[1]
})
blogposts.push({
title: 'blog 3',
tags: ['fun', 'odd'],
author: userIds[2]
})
BlogPost.create(blogposts, function(err, docs) {
assert.ifError(err);
/**
* Population
*/
BlogPost
.find({ tags: 'fun' })
.lean()
.populate('author')
.exec(function(err, docs) {
assert.ifError(err);
/**
* Populate the populated documents
*/
var opts = {
path: 'author.friends',
select: 'name',
options: { limit: 2 }
}
BlogPost.populate(docs, opts, function(err, docs) {
assert.ifError(err);
console.log('populated');
var s = require('util').inspect(docs, { depth: null })
console.log(s);
done();
})
})
})
})
});
function done(err) {
if (err) console.error(err.stack);
mongoose.connection.db.dropDatabase(function() {
mongoose.connection.close();
});
}

95
node_modules/mongoose/examples/population-basic.js generated vendored Normal file
View File

@ -0,0 +1,95 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String
, manufacturer: String
, released: Date
})
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String
, developer: String
, released: Date
, consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }]
})
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
})
/**
* Data generation
*/
function createData () {
Console.create({
name: 'Nintendo 64'
, manufacturer: 'Nintendo'
, released: 'September 29, 1996'
}, function (err, nintendo64) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time'
, developer: 'Nintendo'
, released: new Date('November 21, 1998')
, consoles: [nintendo64]
}, function (err) {
if (err) return done(err);
example();
})
})
}
/**
* Population
*/
function example () {
Game
.findOne({ name: /^Legend of Zelda/ })
.populate('consoles')
.exec(function (err, ocinara) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s'
, ocinara.name
, ocinara.consoles[0].name
, ocinara.released.toLocaleDateString());
done();
})
}
function done (err) {
if (err) console.error(err);
Console.remove(function () {
Game.remove(function () {
mongoose.disconnect();
})
})
}

View File

@ -0,0 +1,101 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String
, manufacturer: String
, released: Date
})
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String
, developer: String
, released: Date
, consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }]
})
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
})
/**
* Data generation
*/
function createData () {
Console.create({
name: 'Nintendo 64'
, manufacturer: 'Nintendo'
, released: 'September 29, 1996'
}, function (err, nintendo64) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time'
, developer: 'Nintendo'
, released: new Date('November 21, 1998')
, consoles: [nintendo64]
}, function (err) {
if (err) return done(err);
example();
})
})
}
/**
* Population
*/
function example () {
Game
.findOne({ name: /^Legend of Zelda/ })
.exec(function (err, ocinara) {
if (err) return done(err);
console.log('"%s" console _id: %s', ocinara.name, ocinara.consoles[0]);
// population of existing document
ocinara.populate('consoles', function (err) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s'
, ocinara.name
, ocinara.consoles[0].name
, ocinara.released.toLocaleDateString());
done();
})
})
}
function done (err) {
if (err) console.error(err);
Console.remove(function () {
Game.remove(function () {
mongoose.disconnect();
})
})
}

View File

@ -0,0 +1,112 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String
, manufacturer: String
, released: Date
})
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String
, developer: String
, released: Date
, consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }]
})
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
})
/**
* Data generation
*/
function createData () {
Console.create({
name: 'Nintendo 64'
, manufacturer: 'Nintendo'
, released: 'September 29, 1996'
}, {
name: 'Super Nintendo'
, manufacturer: 'Nintendo'
, released: 'August 23, 1991'
}, function (err, nintendo64, superNintendo) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time'
, developer: 'Nintendo'
, released: new Date('November 21, 1998')
, consoles: [nintendo64]
}, {
name: 'Mario Kart'
, developer: 'Nintendo'
, released: 'September 1, 1992'
, consoles: [superNintendo]
}, function (err) {
if (err) return done(err);
example();
})
})
}
/**
* Population
*/
function example () {
Game
.find({})
.exec(function (err, games) {
if (err) return done(err);
console.log('found %d games', games.length);
var options = { path: 'consoles', select: 'name released -_id' };
Game.populate(games, options, function (err, games) {
if (err) return done(err);
games.forEach(function (game) {
console.log(
'"%s" was released for the %s on %s'
, game.name
, game.consoles[0].name
, game.released.toLocaleDateString());
})
done()
})
})
}
function done (err) {
if (err) console.error(err);
Console.remove(function () {
Game.remove(function () {
mongoose.disconnect();
})
})
}

124
node_modules/mongoose/examples/population-options.js generated vendored Normal file
View File

@ -0,0 +1,124 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String
, manufacturer: String
, released: Date
})
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String
, developer: String
, released: Date
, consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }]
})
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
})
/**
* Data generation
*/
function createData () {
Console.create({
name: 'Nintendo 64'
, manufacturer: 'Nintendo'
, released: 'September 29, 1996'
}, {
name: 'Super Nintendo'
, manufacturer: 'Nintendo'
, released: 'August 23, 1991'
}, {
name: 'XBOX 360'
, manufacturer: 'Microsoft'
, released: 'November 22, 2005'
}, function (err, nintendo64, superNintendo, xbox360) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time'
, developer: 'Nintendo'
, released: new Date('November 21, 1998')
, consoles: [nintendo64]
}, {
name: 'Mario Kart'
, developer: 'Nintendo'
, released: 'September 1, 1992'
, consoles: [superNintendo]
}, {
name: 'Perfect Dark Zero'
, developer: 'Rare'
, released: 'November 17, 2005'
, consoles: [xbox360]
}, function (err) {
if (err) return done(err);
example();
})
})
}
/**
* Population
*/
function example () {
Game
.find({})
.populate({
path: 'consoles'
, match: { manufacturer: 'Nintendo' }
, select: 'name'
, options: { comment: 'population' }
})
.exec(function (err, games) {
if (err) return done(err);
games.forEach(function (game) {
console.log(
'"%s" was released for the %s on %s'
, game.name
, game.consoles.length ? game.consoles[0].name : '??'
, game.released.toLocaleDateString());
})
return done();
})
}
/**
* Clean up
*/
function done (err) {
if (err) console.error(err);
Console.remove(function () {
Game.remove(function () {
mongoose.disconnect();
})
})
}

View File

@ -0,0 +1,96 @@
var mongoose = require('mongoose')
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String
, manufacturer: String
, released: Date
})
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String
, developer: String
, released: Date
, consoles: [{ type: Schema.Types.ObjectId, ref: 'Console' }]
})
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function (err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
})
/**
* Data generation
*/
function createData () {
Console.create({
name: 'Nintendo 64'
, manufacturer: 'Nintendo'
, released: 'September 29, 1996'
}, function (err, nintendo64) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time'
, developer: 'Nintendo'
, released: new Date('November 21, 1998')
, consoles: [nintendo64]
}, function (err) {
if (err) return done(err);
example();
})
})
}
/**
* Population
*/
function example () {
Game
.findOne({ name: /^Legend of Zelda/ })
.populate('consoles')
.lean() // just return plain objects, not documents wrapped by mongoose
.exec(function (err, ocinara) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s'
, ocinara.name
, ocinara.consoles[0].name
, ocinara.released.toLocaleDateString());
done();
})
}
function done (err) {
if (err) console.error(err);
Console.remove(function () {
Game.remove(function () {
mongoose.disconnect();
})
})
}

102
node_modules/mongoose/examples/schema.js generated vendored Normal file
View File

@ -0,0 +1,102 @@
/**
* Module dependencies.
*/
var mongoose = require('mongoose')
, Schema = mongoose.Schema;
/**
* Schema definition
*/
// recursive embedded-document schema
var Comment = new Schema();
Comment.add({
title : { type: String, index: true }
, date : Date
, body : String
, comments : [Comment]
});
var BlogPost = new Schema({
title : { type: String, index: true }
, slug : { type: String, lowercase: true, trim: true }
, date : Date
, buf : Buffer
, comments : [Comment]
, creator : Schema.ObjectId
});
var Person = new Schema({
name: {
first: String
, last : String
}
, email: { type: String, required: true, index: { unique: true, sparse: true } }
, alive: Boolean
});
/**
* Accessing a specific schema type by key
*/
BlogPost.path('date')
.default(function(){
return new Date()
})
.set(function(v){
return v == 'now' ? new Date() : v;
});
/**
* Pre hook.
*/
BlogPost.pre('save', function(next, done){
emailAuthor(done); // some async function
next();
});
/**
* Methods
*/
BlogPost.methods.findCreator = function (callback) {
return this.db.model('Person').findById(this.creator, callback);
}
BlogPost.statics.findByTitle = function (title, callback) {
return this.find({ title: title }, callback);
}
BlogPost.methods.expressiveQuery = function (creator, date, callback) {
return this.find('creator', creator).where('date').gte(date).run(callback);
}
/**
* Plugins
*/
function slugGenerator (options){
options = options || {};
var key = options.key || 'title';
return function slugGenerator(schema){
schema.path(key).set(function(v){
this.slug = v.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/-+/g, '');
return v;
});
};
};
BlogPost.plugin(slugGenerator());
/**
* Define model.
*/
mongoose.model('BlogPost', BlogPost);
mongoose.model('Person', Person);

7
node_modules/mongoose/index.js generated vendored Normal file
View File

@ -0,0 +1,7 @@
/**
* Export lib/mongoose
*
*/
module.exports = require('./lib/');

188
node_modules/mongoose/lib/collection.js generated vendored Normal file
View File

@ -0,0 +1,188 @@
/*!
* Module dependencies.
*/
var STATES = require('./connectionstate')
/**
* Abstract Collection constructor
*
* This is the base class that drivers inherit from and implement.
*
* @param {String} name name of the collection
* @param {Connection} conn A MongooseConnection instance
* @param {Object} opts optional collection options
* @api public
*/
function Collection (name, conn, opts) {
if (undefined === opts) opts = {};
if (undefined === opts.capped) opts.capped = {};
opts.bufferCommands = undefined === opts.bufferCommands
? true
: opts.bufferCommands;
if ('number' == typeof opts.capped) {
opts.capped = { size: opts.capped };
}
this.opts = opts;
this.name = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
if (STATES.connected == this.conn.readyState) {
this.onOpen();
}
};
/**
* The collection name
*
* @api public
* @property name
*/
Collection.prototype.name;
/**
* The Connection instance
*
* @api public
* @property conn
*/
Collection.prototype.conn;
/**
* Called when the database connects
*
* @api private
*/
Collection.prototype.onOpen = function () {
var self = this;
this.buffer = false;
self.doQueue();
};
/**
* Called when the database disconnects
*
* @api private
*/
Collection.prototype.onClose = function () {
if (this.opts.bufferCommands) {
this.buffer = true;
}
};
/**
* Queues a method for later execution when its
* database connection opens.
*
* @param {String} name name of the method to queue
* @param {Array} args arguments to pass to the method when executed
* @api private
*/
Collection.prototype.addQueue = function (name, args) {
this.queue.push([name, args]);
return this;
};
/**
* Executes all queued methods and clears the queue.
*
* @api private
*/
Collection.prototype.doQueue = function () {
for (var i = 0, l = this.queue.length; i < l; i++){
this[this.queue[i][0]].apply(this, this.queue[i][1]);
}
this.queue = [];
return this;
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.ensureIndex = function(){
throw new Error('Collection#ensureIndex unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.findAndModify = function(){
throw new Error('Collection#findAndModify unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.findOne = function(){
throw new Error('Collection#findOne unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.find = function(){
throw new Error('Collection#find unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.insert = function(){
throw new Error('Collection#insert unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.save = function(){
throw new Error('Collection#save unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.update = function(){
throw new Error('Collection#update unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.getIndexes = function(){
throw new Error('Collection#getIndexes unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.mapReduce = function(){
throw new Error('Collection#mapReduce unimplemented by driver');
};
/*!
* Module exports.
*/
module.exports = Collection;

706
node_modules/mongoose/lib/connection.js generated vendored Normal file
View File

@ -0,0 +1,706 @@
/*!
* Module dependencies.
*/
var url = require('url')
, utils = require('./utils')
, EventEmitter = require('events').EventEmitter
, driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native'
, Model = require('./model')
, Schema = require('./schema')
, Collection = require(driver + '/collection')
, STATES = require('./connectionstate')
, MongooseError = require('./error')
, assert =require('assert')
, muri = require('muri')
/*!
* Protocol prefix regexp.
*
* @api private
*/
var rgxProtocol = /^(?:.)+:\/\//;
/**
* Connection constructor
*
* For practical reasons, a Connection equals a Db.
*
* @param {Mongoose} base a mongoose instance
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `connecting`: Emitted when `connection.{open,openSet}()` is executed on this connection.
* @event `connected`: Emitted when this connection successfully connects to the db. May be emitted _multiple_ times in `reconnected` scenarios.
* @event `open`: Emitted after we `connected` and `onOpen` is executed on all of this connections models.
* @event `disconnecting`: Emitted when `connection.close()` was executed.
* @event `disconnected`: Emitted after getting disconnected from the db.
* @event `close`: Emitted after we `disconnected` and `onClose` executed on all of this connections models.
* @event `reconnected`: Emitted after we `connected` and subsequently `disconnected`, followed by successfully another successfull connection.
* @event `error`: Emitted when an error occurs on this connection.
* @event `fullsetup`: Emitted in a replica-set scenario, when all nodes specified in the connection string are connected.
* @api public
*/
function Connection (base) {
this.base = base;
this.collections = {};
this.models = {};
this.replica = false;
this.hosts = null;
this.host = null;
this.port = null;
this.user = null;
this.pass = null;
this.name = null;
this.options = null;
this._readyState = STATES.disconnected;
this._closeCalled = false;
this._hasOpened = false;
};
/*!
* Inherit from EventEmitter
*/
Connection.prototype.__proto__ = EventEmitter.prototype;
/**
* Connection ready state
*
* - 0 = disconnected
* - 1 = connected
* - 2 = connecting
* - 3 = disconnecting
*
* Each state change emits its associated event name.
*
* ####Example
*
* conn.on('connected', callback);
* conn.on('disconnected', callback);
*
* @property readyState
* @api public
*/
Object.defineProperty(Connection.prototype, 'readyState', {
get: function(){ return this._readyState; }
, set: function (val) {
if (!(val in STATES)) {
throw new Error('Invalid connection state: ' + val);
}
if (this._readyState !== val) {
this._readyState = val;
if (STATES.connected === val)
this._hasOpened = true;
this.emit(STATES[val]);
}
}
});
/**
* A hash of the collections associated with this connection
*
* @property collections
*/
Connection.prototype.collections;
/**
* The mongodb.Db instance, set when the connection is opened
*
* @property db
*/
Connection.prototype.db;
/**
* Opens the connection to MongoDB.
*
* `options` is a hash with the following possible properties:
*
* db - passed to the connection db instance
* server - passed to the connection server instance(s)
* replset - passed to the connection ReplSet instance
* user - username for authentication
* pass - password for authentication
* auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate)
*
* ####Notes:
*
* Mongoose forces the db option `forceServerObjectId` false and cannot be overridden.
* Mongoose defaults the server `auto_reconnect` options to true which can be overridden.
* See the node-mongodb-native driver instance for options that it understands.
*
* _Options passed take precedence over options included in connection strings._
*
* @param {String} connection_string mongodb://uri or the host to which you are connecting
* @param {String} [database] database name
* @param {Number} [port] database port
* @param {Object} [options] options
* @param {Function} [callback]
* @see node-mongodb-native https://github.com/mongodb/node-mongodb-native
* @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate
* @api public
*/
Connection.prototype.open = function (host, database, port, options, callback) {
var self = this
, parsed
, uri;
if ('string' === typeof database) {
switch (arguments.length) {
case 2:
port = 27017;
case 3:
switch (typeof port) {
case 'function':
callback = port, port = 27017;
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, database = undefined;
break;
case 'object':
options = database;
database = undefined;
callback = port;
break;
}
if (!rgxProtocol.test(host)) {
host = 'mongodb://' + host;
}
try {
parsed = muri(host);
} catch (err) {
this.error(err, callback);
return this;
}
database = parsed.db;
host = parsed.hosts[0].host || parsed.hosts[0].ipc;
port = parsed.hosts[0].port || 27017;
}
this.options = this.parseOptions(options, parsed && parsed.options);
// make sure we can open
if (STATES.disconnected !== this.readyState) {
var err = new Error('Trying to open unclosed connection.');
err.state = this.readyState;
this.error(err, callback);
return this;
}
if (!host) {
this.error(new Error('Missing hostname.'), callback);
return this;
}
if (!database) {
this.error(new Error('Missing database name.'), callback);
return this;
}
// authentication
if (options && options.user && options.pass) {
this.user = options.user;
this.pass = options.pass;
} else if (parsed && parsed.auth) {
this.user = parsed.auth.user;
this.pass = parsed.auth.pass;
// Check hostname for user/pass
} else if (/@/.test(host) && /:/.test(host.split('@')[0])) {
host = host.split('@');
var auth = host.shift().split(':');
host = host.pop();
this.user = auth[0];
this.pass = auth[1];
} else {
this.user = this.pass = undefined;
}
this.name = database;
this.host = host;
this.port = port;
this._open(callback);
return this;
};
/**
* Opens the connection to a replica set.
*
* ####Example:
*
* var db = mongoose.createConnection();
* db.openSet("mongodb://user:pwd@localhost:27020/testing,mongodb://example.com:27020,mongodb://localhost:27019");
*
* The database name and/or auth need only be included in one URI.
* The `options` is a hash which is passed to the internal driver connection object.
*
* Valid `options`
*
* db - passed to the connection db instance
* server - passed to the connection server instance(s)
* replset - passed to the connection ReplSetServer instance
* user - username for authentication
* pass - password for authentication
* auth - options for authentication (see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate)
*
* _Options passed take precedence over options included in connection strings._
*
* ####Notes:
*
* Mongoose forces the db option `forceServerObjectId` false and cannot be overridden.
* Mongoose defaults the server `auto_reconnect` options to true which can be overridden.
* See the node-mongodb-native driver instance for options that it understands.
*
* @param {String} uris comma-separated mongodb:// `URI`s
* @param {String} [database] database name if not included in `uris`
* @param {Object} [options] passed to the internal driver
* @param {Function} [callback]
* @see node-mongodb-native https://github.com/mongodb/node-mongodb-native
* @see http://mongodb.github.com/node-mongodb-native/api-generated/db.html#authenticate
* @api public
*/
Connection.prototype.openSet = function (uris, database, options, callback) {
if (!rgxProtocol.test(uris)) {
uris = 'mongodb://' + uris;
}
var self = this;
switch (arguments.length) {
case 3:
switch (typeof database) {
case 'string':
this.name = database;
break;
case 'object':
callback = options;
options = database;
database = null;
break;
}
if ('function' === typeof options) {
callback = options;
options = {};
}
break;
case 2:
switch (typeof database) {
case 'string':
this.name = database;
break;
case 'function':
callback = database, database = null;
break;
case 'object':
options = database, database = null;
break;
}
}
var parsed;
try {
parsed = muri(uris);
} catch (err) {
this.error(err, callback);
return this;
}
if (!this.name) {
this.name = parsed.db;
}
this.hosts = parsed.hosts;
this.options = this.parseOptions(options, parsed && parsed.options);
this.replica = true;
if (!this.name) {
this.error(new Error('No database name provided for replica set'), callback);
return this;
}
// authentication
if (options && options.user && options.pass) {
this.user = options.user;
this.pass = options.pass;
} else if (parsed && parsed.auth) {
this.user = parsed.auth.user;
this.pass = parsed.auth.pass;
} else {
this.user = this.pass = undefined;
}
this._open(callback);
return this;
};
/**
* error
*
* Graceful error handling, passes error to callback
* if available, else emits error on the connection.
*
* @param {Error} err
* @param {Function} callback optional
* @api private
*/
Connection.prototype.error = function (err, callback) {
if (callback) return callback(err);
this.emit('error', err);
}
/**
* Handles opening the connection with the appropriate method based on connection type.
*
* @param {Function} callback
* @api private
*/
Connection.prototype._open = function (callback) {
this.readyState = STATES.connecting;
this._closeCalled = false;
var self = this;
var method = this.replica
? 'doOpenSet'
: 'doOpen';
// open connection
this[method](function (err) {
if (err) {
self.readyState = STATES.disconnected;
if (self._hasOpened) {
if (callback) callback(err);
} else {
self.error(err, callback);
}
return;
}
self.onOpen(callback);
});
}
/**
* Called when the connection is opened
*
* @api private
*/
Connection.prototype.onOpen = function (callback) {
var self = this;
function open (err) {
if (err) {
self.readyState = STATES.disconnected;
if (self._hasOpened) {
if (callback) callback(err);
} else {
self.error(err, callback);
}
return;
}
self.readyState = STATES.connected;
// avoid having the collection subscribe to our event emitter
// to prevent 0.3 warning
for (var i in self.collections)
self.collections[i].onOpen();
callback && callback();
self.emit('open');
};
// re-authenticate
if (self.user && self.pass) {
self.db.authenticate(self.user, self.pass, self.options.auth, open);
}
else
open();
};
/**
* Closes the connection
*
* @param {Function} [callback] optional
* @return {Connection} self
* @api public
*/
Connection.prototype.close = function (callback) {
var self = this;
this._closeCalled = true;
switch (this.readyState){
case 0: // disconnected
callback && callback();
break;
case 1: // connected
this.readyState = STATES.disconnecting;
this.doClose(function(err){
if (err){
self.error(err, callback);
} else {
self.onClose();
callback && callback();
}
});
break;
case 2: // connecting
this.once('open', function(){
self.close(callback);
});
break;
case 3: // disconnecting
if (!callback) break;
this.once('close', function () {
callback();
});
break;
}
return this;
};
/**
* Called when the connection closes
*
* @api private
*/
Connection.prototype.onClose = function () {
this.readyState = STATES.disconnected;
// avoid having the collection subscribe to our event emitter
// to prevent 0.3 warning
for (var i in this.collections)
this.collections[i].onClose();
this.emit('close');
};
/**
* Retrieves a collection, creating it if not cached.
*
* Not typically needed by applications. Just talk to your collection through your model.
*
* @param {String} name of the collection
* @param {Object} [options] optional collection options
* @return {Collection} collection instance
* @api public
*/
Connection.prototype.collection = function (name, options) {
if (!(name in this.collections))
this.collections[name] = new Collection(name, this, options);
return this.collections[name];
};
/**
* Defines or retrieves a model.
*
* var mongoose = require('mongoose');
* var db = mongoose.createConnection(..);
* db.model('Venue', new Schema(..));
* var Ticket = db.model('Ticket', new Schema(..));
* var Venue = db.model('Venue');
*
* _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._
*
* ####Example:
*
* var schema = new Schema({ name: String }, { collection: 'actor' });
*
* // or
*
* schema.set('collection', 'actor');
*
* // or
*
* var collectionName = 'actor'
* var M = conn.model('Actor', schema, collectionName)
*
* @param {String} name the model name
* @param {Schema} [schema] a schema. necessary when defining a model
* @param {String} [collection] name of mongodb collection (optional) if not given it will be induced from model name
* @see Mongoose#model #index_Mongoose-model
* @return {Model} The compiled model
* @api public
*/
Connection.prototype.model = function (name, schema, collection) {
// collection name discovery
if ('string' == typeof schema) {
collection = schema;
schema = false;
}
if (utils.isObject(schema) && !(schema instanceof Schema)) {
schema = new Schema(schema);
}
if (this.models[name] && !collection) {
// model exists but we are not subclassing with custom collection
if (schema instanceof Schema && schema != this.models[name].schema) {
throw new MongooseError.OverwriteModelError(name);
}
return this.models[name];
}
var opts = { cache: false, connection: this }
var model;
if (schema instanceof Schema) {
// compile a model
model = this.base.model(name, schema, collection, opts)
// only the first model with this name is cached to allow
// for one-offs with custom collection names etc.
if (!this.models[name]) {
this.models[name] = model;
}
model.init();
return model;
}
if (this.models[name] && collection) {
// subclassing current model with alternate collection
model = this.models[name];
schema = model.prototype.schema;
var sub = model.__subclass(this, schema, collection);
// do not cache the sub model
return sub;
}
// lookup model in mongoose module
model = this.base.models[name];
if (!model) {
throw new MongooseError.MissingSchemaError(name);
}
if (this == model.prototype.db
&& (!collection || collection == model.collection.name)) {
// model already uses this connection.
// only the first model with this name is cached to allow
// for one-offs with custom collection names etc.
if (!this.models[name]) {
this.models[name] = model;
}
return model;
}
return this.models[name] = model.__subclass(this, schema, collection);
}
/**
* Returns an array of model names created on this connection.
* @api public
* @return {Array}
*/
Connection.prototype.modelNames = function () {
return Object.keys(this.models);
}
/**
* Set profiling level.
*
* @param {Number|String} level either off (0), slow (1), or all (2)
* @param {Number} [ms] the threshold in milliseconds above which queries will be logged when in `slow` mode. defaults to 100.
* @param {Function} callback
* @api public
*/
Connection.prototype.setProfiling = function (level, ms, callback) {
if (STATES.connected !== this.readyState) {
return this.on('open', this.setProfiling.bind(this, 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);
});
};
/*!
* Noop.
*/
function noop () {}
/*!
* Module exports.
*/
Connection.STATES = STATES;
module.exports = Connection;

24
node_modules/mongoose/lib/connectionstate.js generated vendored Normal file
View File

@ -0,0 +1,24 @@
/*!
* Connection states
*/
var STATES = module.exports = exports = Object.create(null);
var disconnected = 'disconnected';
var connected = 'connected';
var connecting = 'connecting';
var disconnecting = 'disconnecting';
var uninitialized = 'uninitialized';
STATES[0] = disconnected;
STATES[1] = connected;
STATES[2] = connecting;
STATES[3] = disconnecting;
STATES[99] = uninitialized;
STATES[disconnected] = 0;
STATES[connected] = 1;
STATES[connecting] = 2;
STATES[disconnecting] = 3;
STATES[uninitialized] = 99;

1712
node_modules/mongoose/lib/document.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

4
node_modules/mongoose/lib/drivers/SPEC.md generated vendored Normal file
View File

@ -0,0 +1,4 @@
# Driver Spec
TODO

View File

@ -0,0 +1,8 @@
/*!
* Module dependencies.
*/
var Binary = require('mongodb').BSONPure.Binary;
module.exports = exports = Binary;

View File

@ -0,0 +1,211 @@
/*!
* Module dependencies.
*/
var MongooseCollection = require('../../collection')
, Collection = require('mongodb').Collection
, STATES = require('../../connectionstate')
, utils = require('../../utils')
/**
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
*
* All methods methods from the [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver are copied and wrapped in queue management.
*
* @inherits Collection
* @api private
*/
function NativeCollection () {
this.collection = null;
MongooseCollection.apply(this, arguments);
}
/*!
* Inherit from abstract Collection.
*/
NativeCollection.prototype.__proto__ = MongooseCollection.prototype;
/**
* Called when the connection opens.
*
* @api private
*/
NativeCollection.prototype.onOpen = function () {
var self = this;
// always get a new collection in case the user changed host:port
// of parent db instance when re-opening the connection.
if (!self.opts.capped.size) {
// non-capped
return self.conn.db.collection(self.name, callback);
}
// capped
return self.conn.db.collection(self.name, function (err, c) {
if (err) return callback(err);
// discover if this collection exists and if it is capped
c.options(function (err, exists) {
if (err) return callback(err);
if (exists) {
if (exists.capped) {
callback(null, c);
} else {
var msg = 'A non-capped collection exists with the name: '+ self.name +'\n\n'
+ ' To use this collection as a capped collection, please '
+ 'first convert it.\n'
+ ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped'
err = new Error(msg);
callback(err);
}
} else {
// create
var opts = utils.clone(self.opts.capped);
opts.capped = true;
self.conn.db.createCollection(self.name, opts, callback);
}
});
});
function callback (err, collection) {
if (err) {
// likely a strict mode error
self.conn.emit('error', err);
} else {
self.collection = collection;
MongooseCollection.prototype.onOpen.call(self);
}
};
};
/**
* Called when the connection closes
*
* @api private
*/
NativeCollection.prototype.onClose = function () {
MongooseCollection.prototype.onClose.call(this);
};
/*!
* Copy the collection methods and make them subject to queues
*/
for (var i in Collection.prototype) {
(function(i){
NativeCollection.prototype[i] = function () {
if (this.buffer) {
this.addQueue(i, arguments);
return;
}
var collection = this.collection
, args = arguments
, self = this
, debug = self.conn.base.options.debug;
if (debug) {
if ('function' === typeof debug) {
debug.apply(debug
, [self.name, i].concat(utils.args(args, 0, args.length-1)));
} else {
console.error('\x1B[0;36mMongoose:\x1B[0m %s.%s(%s) %s %s %s'
, self.name
, i
, print(args[0])
, print(args[1])
, print(args[2])
, print(args[3]))
}
}
collection[i].apply(collection, args);
};
})(i);
}
/*!
* Debug print helper
*/
function print (arg) {
var type = typeof arg;
if ('function' === type || 'undefined' === type) return '';
return format(arg);
}
/*!
* Debug print helper
*/
function format (obj, sub) {
var x = utils.clone(obj);
if (x) {
if ('Binary' === x.constructor.name) {
x = '[object Buffer]';
} else if ('ObjectID' === x.constructor.name) {
var representation = 'ObjectId("' + x.toHexString() + '")';
x = { inspect: function() { return representation; } };
} else if ('Date' === x.constructor.name) {
var representation = 'new Date("' + x.toUTCString() + '")';
x = { inspect: function() { return representation; } };
} else if ('Object' === x.constructor.name) {
var keys = Object.keys(x)
, i = keys.length
, key
while (i--) {
key = keys[i];
if (x[key]) {
if ('Binary' === x[key].constructor.name) {
x[key] = '[object Buffer]';
} else if ('Object' === x[key].constructor.name) {
x[key] = format(x[key], true);
} else if ('ObjectID' === x[key].constructor.name) {
;(function(x){
var representation = 'ObjectId("' + x[key].toHexString() + '")';
x[key] = { inspect: function() { return representation; } };
})(x)
} else if ('Date' === x[key].constructor.name) {
;(function(x){
var representation = 'new Date("' + x[key].toUTCString() + '")';
x[key] = { inspect: function() { return representation; } };
})(x)
} else if (Array.isArray(x[key])) {
x[key] = x[key].map(function (o) {
return format(o, true)
});
}
}
}
}
if (sub) return x;
}
return require('util')
.inspect(x, false, 10, true)
.replace(/\n/g, '')
.replace(/\s{2,}/g, ' ')
}
/**
* Retreives information about this collections indexes.
*
* @param {Function} callback
* @method getIndexes
* @api public
*/
NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation;
/*!
* Module exports.
*/
module.exports = NativeCollection;

View File

@ -0,0 +1,303 @@
/*!
* Module dependencies.
*/
var MongooseConnection = require('../../connection')
, mongo = require('mongodb')
, Db = mongo.Db
, Server = mongo.Server
, Mongos = mongo.Mongos
, STATES = require('../../connectionstate')
, ReplSetServers = mongo.ReplSetServers;
/**
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
*
* @inherits Connection
* @api private
*/
function NativeConnection() {
MongooseConnection.apply(this, arguments);
this._listening = false;
};
/*!
* Inherits from Connection.
*/
NativeConnection.prototype.__proto__ = MongooseConnection.prototype;
/**
* Opens the connection to MongoDB.
*
* @param {Function} fn
* @return {Connection} this
* @api private
*/
NativeConnection.prototype.doOpen = function (fn) {
if (this.db) {
mute(this);
}
var server = new Server(this.host, this.port, this.options.server);
this.db = new Db(this.name, server, this.options.db);
var self = this;
this.db.open(function (err) {
if (err) return fn(err);
listen(self);
fn();
});
return this;
};
/*!
* Register listeners for important events and bubble appropriately.
*/
function listen (conn) {
if (conn._listening) return;
conn._listening = true;
conn.db.on('close', function(){
if (conn._closeCalled) return;
// the driver never emits an `open` event. auto_reconnect still
// emits a `close` event but since we never get another
// `open` we can't emit close
if (conn.db.serverConfig.autoReconnect) {
conn.readyState = STATES.disconnected;
conn.emit('close');
return;
}
conn.onClose();
});
conn.db.on('error', function(err){
conn.emit('error', err);
});
conn.db.on('timeout', function(err){
var error = new Error(err && err.err || 'connection timeout');
conn.emit('error', error);
});
conn.db.on('open', function (err, db) {
if (STATES.disconnected === conn.readyState && db && db.databaseName) {
conn.readyState = STATES.connected;
conn.emit('reconnected')
}
})
}
/*!
* Remove listeners registered in `listen`
*/
function mute (conn) {
if (!conn.db) throw new Error('missing db');
conn.db.removeAllListeners("close");
conn.db.removeAllListeners("error");
conn.db.removeAllListeners("timeout");
conn.db.removeAllListeners("open");
conn.db.removeAllListeners("fullsetup");
conn._listening = false;
}
/**
* Opens a connection to a MongoDB ReplicaSet.
*
* See description of [doOpen](#NativeConnection-doOpen) for server options. In this case `options.replset` is also passed to ReplSetServers.
*
* @param {Function} fn
* @api private
* @return {Connection} this
*/
NativeConnection.prototype.doOpenSet = function (fn) {
if (this.db) {
mute(this);
}
var servers = []
, self = this;
this.hosts.forEach(function (server) {
var host = server.host || server.ipc;
var port = server.port || 27017;
servers.push(new Server(host, port, self.options.server));
})
var server = this.options.mongos
? new Mongos(servers, this.options.mongos)
: new ReplSetServers(servers, this.options.replset);
this.db = new Db(this.name, server, this.options.db);
this.db.on('fullsetup', function () {
self.emit('fullsetup')
});
this.db.open(function (err) {
if (err) return fn(err);
fn();
listen(self);
});
return this;
};
/**
* Closes the connection
*
* @param {Function} fn
* @return {Connection} this
* @api private
*/
NativeConnection.prototype.doClose = function (fn) {
this.db.close();
if (fn) fn();
return this;
}
/**
* Prepares default connection options for the node-mongodb-native driver.
*
* _NOTE: `passed` options take precedence over connection string options._
*
* @param {Object} passed options that were passed directly during connection
* @param {Object} [connStrOptions] options that were passed in the connection string
* @api private
*/
NativeConnection.prototype.parseOptions = function (passed, connStrOpts) {
var o = passed || {};
o.db || (o.db = {});
o.auth || (o.auth = {});
o.server || (o.server = {});
o.replset || (o.replset = {});
o.server.socketOptions || (o.server.socketOptions = {});
o.replset.socketOptions || (o.replset.socketOptions = {});
var opts = connStrOpts || {};
Object.keys(opts).forEach(function (name) {
switch (name) {
case 'poolSize':
if ('undefined' == typeof o.server.poolSize) {
o.server.poolSize = o.replset.poolSize = opts[name];
}
break;
case 'slaveOk':
if ('undefined' == typeof o.server.slave_ok) {
o.server.slave_ok = opts[name];
}
break;
case 'autoReconnect':
if ('undefined' == typeof o.server.auto_reconnect) {
o.server.auto_reconnect = opts[name];
}
break;
case 'ssl':
case 'socketTimeoutMS':
case 'connectTimeoutMS':
if ('undefined' == typeof o.server.socketOptions[name]) {
o.server.socketOptions[name] = o.replset.socketOptions[name] = opts[name];
}
break;
case 'authdb':
if ('undefined' == typeof o.auth.authdb) {
o.auth.authdb = opts[name];
}
break;
case 'authSource':
if ('undefined' == typeof o.auth.authSource) {
o.auth.authSource = opts[name];
}
break;
case 'retries':
case 'reconnectWait':
case 'rs_name':
if ('undefined' == typeof o.replset[name]) {
o.replset[name] = opts[name];
}
break;
case 'replicaSet':
if ('undefined' == typeof o.replset.rs_name) {
o.replset.rs_name = opts[name];
}
break;
case 'readSecondary':
if ('undefined' == typeof o.replset.read_secondary) {
o.replset.read_secondary = opts[name];
}
break;
case 'nativeParser':
if ('undefined' == typeof o.db.native_parser) {
o.db.native_parser = opts[name];
}
break;
case 'w':
case 'safe':
case 'fsync':
case 'journal':
case 'wtimeoutMS':
if ('undefined' == typeof o.db[name]) {
o.db[name] = opts[name];
}
break;
case 'readPreference':
if ('undefined' == typeof o.db.read_preference) {
o.db.read_preference = opts[name];
}
break;
case 'readPreferenceTags':
if ('undefined' == typeof o.db.read_preference_tags) {
o.db.read_preference_tags = opts[name];
}
break;
}
})
if (!('auto_reconnect' in o.server)) {
o.server.auto_reconnect = true;
}
if (!o.db.read_preference) {
// read from primaries by default
o.db.read_preference = 'primary';
}
// mongoose creates its own ObjectIds
o.db.forceServerObjectId = false;
// default safe using new nomenclature
if (!('journal' in o.db || 'j' in o.db ||
'fsync' in o.db || 'safe' in o.db || 'w' in o.db)) {
o.db.w = 1;
}
validate(o);
return o;
}
/*!
* Validates the driver db options.
*
* @param {Object} o
*/
function validate (o) {
if (-1 === o.db.w || 0 === o.db.w) {
if (o.db.journal || o.db.fsync || o.db.safe) {
throw new Error(
'Invalid writeConcern: '
+ 'w set to -1 or 0 cannot be combined with safe|fsync|journal');
}
}
}
/*!
* Module exports.
*/
module.exports = NativeConnection;

View File

@ -0,0 +1,29 @@
/*!
* [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
* @constructor NodeMongoDbObjectId
* @see ObjectId
*/
var ObjectId = require('mongodb').BSONPure.ObjectID;
/*!
* ignore
*/
var ObjectIdToString = ObjectId.toString.bind(ObjectId);
module.exports = exports = ObjectId;
ObjectId.fromString = function(str){
// patch native driver bug in V0.9.6.4
if (!('string' === typeof str && 24 === str.length)) {
throw new Error("Invalid ObjectId");
}
return ObjectId.createFromHexString(str);
};
ObjectId.toString = function(oid){
if (!arguments.length) return ObjectIdToString();
return oid.toHexString();
};

39
node_modules/mongoose/lib/error.js generated vendored Normal file
View File

@ -0,0 +1,39 @@
/**
* MongooseError constructor
*
* @param {String} msg Error message
* @inherits Error https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error
*/
function MongooseError (msg) {
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.message = msg;
this.name = 'MongooseError';
};
/*!
* Inherits from Error.
*/
MongooseError.prototype.__proto__ = Error.prototype;
/*!
* Module exports.
*/
module.exports = exports = MongooseError;
/*!
* Expose subclasses
*/
MongooseError.CastError = require('./errors/cast');
MongooseError.DocumentError = require('./errors/document');
MongooseError.ValidationError = require('./errors/validation')
MongooseError.ValidatorError = require('./errors/validator')
MongooseError.VersionError =require('./errors/version')
MongooseError.OverwriteModelError = require('./errors/overwriteModel')
MongooseError.MissingSchemaError = require('./errors/missingSchema')
MongooseError.DivergentArrayError = require('./errors/divergentArray')

35
node_modules/mongoose/lib/errors/cast.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/**
* Casting Error constructor.
*
* @param {String} type
* @param {String} value
* @inherits MongooseError
* @api private
*/
function CastError (type, value, path) {
MongooseError.call(this, 'Cast to ' + type + ' failed for value "' + value + '" at path "' + path + '"');
Error.captureStackTrace(this, arguments.callee);
this.name = 'CastError';
this.type = type;
this.value = value;
this.path = path;
};
/*!
* Inherits from MongooseError.
*/
CastError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = CastError;

40
node_modules/mongoose/lib/errors/divergentArray.js generated vendored Normal file
View File

@ -0,0 +1,40 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/*!
* DivergentArrayError constructor.
*
* @inherits MongooseError
*/
function DivergentArrayError (paths) {
var msg = 'For your own good, using `document.save()` to update an array '
+ 'which was selected using an $elemMatch projection OR '
+ 'populated using skip, limit, query conditions, or exclusion of '
+ 'the _id field when the operation results in a $pop or $set of '
+ 'the entire array is not supported. The following '
+ 'path(s) would have been modified unsafely:\n'
+ ' ' + paths.join('\n ') + '\n'
+ 'Use Model.update() to update these arrays instead.'
// TODO write up a docs page (FAQ) and link to it
MongooseError.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
this.name = 'DivergentArrayError';
};
/*!
* Inherits from MongooseError.
*/
DivergentArrayError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = DivergentArrayError;

32
node_modules/mongoose/lib/errors/document.js generated vendored Normal file
View File

@ -0,0 +1,32 @@
/*!
* Module requirements
*/
var MongooseError = require('../error')
/**
* Document Error
*
* @param {String} msg
* @inherits MongooseError
* @api private
*/
function DocumentError (msg) {
MongooseError.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
this.name = 'DocumentError';
};
/*!
* Inherits from MongooseError.
*/
DocumentError.prototype.__proto__ = MongooseError.prototype;
/*!
* Module exports.
*/
module.exports = exports = DocumentError;

32
node_modules/mongoose/lib/errors/missingSchema.js generated vendored Normal file
View File

@ -0,0 +1,32 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/*!
* MissingSchema Error constructor.
*
* @inherits MongooseError
*/
function MissingSchemaError (name) {
var msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)';
MongooseError.call(this, msg);
Error.captureStackTrace(this, arguments.callee);
this.name = 'MissingSchemaError';
};
/*!
* Inherits from MongooseError.
*/
MissingSchemaError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = MissingSchemaError;

30
node_modules/mongoose/lib/errors/overwriteModel.js generated vendored Normal file
View File

@ -0,0 +1,30 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/*!
* OverwriteModel Error constructor.
*
* @inherits MongooseError
*/
function OverwriteModelError (name) {
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
Error.captureStackTrace(this, arguments.callee);
this.name = 'OverwriteModelError';
};
/*!
* Inherits from MongooseError.
*/
OverwriteModelError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = OverwriteModelError;

49
node_modules/mongoose/lib/errors/validation.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
/*!
* Module requirements
*/
var MongooseError = require('../error')
/**
* Document Validation Error
*
* @api private
* @param {Document} instance
* @inherits MongooseError
*/
function ValidationError (instance) {
MongooseError.call(this, "Validation failed");
Error.captureStackTrace(this, arguments.callee);
this.name = 'ValidationError';
this.errors = instance.errors = {};
};
/**
* Console.log helper
*/
ValidationError.prototype.toString = function () {
var ret = this.name + ': ';
var msgs = [];
Object.keys(this.errors).forEach(function (key) {
if (this == this.errors[key]) return;
msgs.push(String(this.errors[key]));
}, this)
return ret + msgs.join(', ');
};
/*!
* Inherits from MongooseError.
*/
ValidationError.prototype.__proto__ = MongooseError.prototype;
/*!
* Module exports
*/
module.exports = exports = ValidationError;

51
node_modules/mongoose/lib/errors/validator.js generated vendored Normal file
View File

@ -0,0 +1,51 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/**
* Schema validator error
*
* @param {String} path
* @param {String} msg
* @param {String|Number|any} val
* @inherits MongooseError
* @api private
*/
function ValidatorError (path, type, val) {
var msg = type
? '"' + type + '" '
: '';
var message = 'Validator ' + msg + 'failed for path ' + path
if (2 < arguments.length) message += ' with value `' + String(val) + '`';
MongooseError.call(this, message);
Error.captureStackTrace(this, arguments.callee);
this.name = 'ValidatorError';
this.path = path;
this.type = type;
this.value = val;
};
/*!
* toString helper
*/
ValidatorError.prototype.toString = function () {
return this.message;
}
/*!
* Inherits from MongooseError
*/
ValidatorError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = ValidatorError;

31
node_modules/mongoose/lib/errors/version.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
/*!
* Module dependencies.
*/
var MongooseError = require('../error');
/**
* Version Error constructor.
*
* @inherits MongooseError
* @api private
*/
function VersionError () {
MongooseError.call(this, 'No matching document found.');
Error.captureStackTrace(this, arguments.callee);
this.name = 'VersionError';
};
/*!
* Inherits from MongooseError.
*/
VersionError.prototype.__proto__ = MongooseError.prototype;
/*!
* exports
*/
module.exports = VersionError;

580
node_modules/mongoose/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,580 @@
/*!
* Module dependencies.
*/
var Schema = require('./schema')
, SchemaType = require('./schematype')
, VirtualType = require('./virtualtype')
, SchemaTypes = Schema.Types
, SchemaDefaults = require('./schemadefault')
, Types = require('./types')
, Query = require('./query')
, Promise = require('./promise')
, Model = require('./model')
, Document = require('./document')
, utils = require('./utils')
, format = utils.toCollectionName
, mongodb = require('mongodb')
/**
* Mongoose constructor.
*
* The exports object of the `mongoose` module is an instance of this class.
* Most apps will only use this one instance.
*
* @api public
*/
function Mongoose () {
this.connections = [];
this.plugins = [];
this.models = {};
this.modelSchemas = {};
this.options = {};
this.createConnection(); // default connection
};
/**
* Sets mongoose options
*
* ####Example:
*
* mongoose.set('test', value) // sets the 'test' option to `value`
*
* mongoose.set('debug', true) // enable logging collection methods + arguments to the console
*
* @param {String} key
* @param {String} value
* @api public
*/
Mongoose.prototype.set = function (key, value) {
if (arguments.length == 1)
return this.options[key];
this.options[key] = value;
return this;
};
/**
* Gets mongoose options
*
* ####Example:
*
* mongoose.get('test') // returns the 'test' value
*
* @param {String} key
* @method get
* @api public
*/
Mongoose.prototype.get = Mongoose.prototype.set;
/*!
* ReplSet connection string check.
*/
var rgxReplSet = /^.+,.+$/;
/**
* Creates a Connection instance.
*
* Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
*
* If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately. This means we can pass `db`, `server`, and `replset` options to the driver.
*
* _Options passed take precedence over options included in connection strings._
*
* ####Example:
*
* // with mongodb:// URI
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
*
* // and options
* var opts = { db: { native_parser: true }}
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
*
* // replica sets
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port');
*
* // and options
* var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database,mongodb://anotherhost:port,mongodb://yetanother:port', opts);
*
* // with [host, database_name[, port] signature
* db = mongoose.createConnection('localhost', 'database', port)
*
* // and options
* var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
* db = mongoose.createConnection('localhost', 'database', port, opts)
*
* // initialize now, connect later
* db = mongoose.createConnection();
* db.open('localhost', 'database', port, [opts]);
*
* @param {String} [uri] a mongodb:// URI
* @param {Object} [options] options to pass to the driver
* @see Connection#open #connection_Connection-open
* @see Connection#openSet #connection_Connection-openSet
* @return {Connection} the created Connection object
* @api public
*/
Mongoose.prototype.createConnection = function () {
var conn = new Connection(this);
this.connections.push(conn);
if (arguments.length) {
if (rgxReplSet.test(arguments[0])) {
conn.openSet.apply(conn, arguments);
} else {
conn.open.apply(conn, arguments);
}
}
return conn;
};
/**
* Opens the default mongoose connection.
*
* If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately.
*
* _Options passed take precedence over options included in connection strings._
*
* @see Mongoose#createConnection #index_Mongoose-createConnection
* @api public
* @return {Mongoose} this
*/
Mongoose.prototype.connect = function () {
var conn = this.connection;
if (rgxReplSet.test(arguments[0])) {
conn.openSet.apply(conn, arguments);
} else {
conn.open.apply(conn, arguments);
}
return this;
};
/**
* Disconnects all connections.
*
* @param {Function} [fn] called after all connection close.
* @return {Mongoose} this
* @api public
*/
Mongoose.prototype.disconnect = function (fn) {
var count = this.connections.length
, error
this.connections.forEach(function(conn){
conn.close(function(err){
if (error) return;
if (err) {
error = err;
if (fn) return fn(err);
throw err;
}
if (fn)
--count || fn();
});
});
return this;
};
/**
* Defines a model or retrieves it.
*
* Models defined on the `mongoose` instance are available to all connection created by the same `mongoose` instance.
*
* ####Example:
*
* var mongoose = require('mongoose');
*
* // define an Actor model with this mongoose instance
* mongoose.model('Actor', new Schema({ name: String }));
*
* // create a new connection
* var conn = mongoose.createConnection(..);
*
* // retrieve the Actor model
* var Actor = conn.model('Actor');
*
* _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._
*
* ####Example:
*
* var schema = new Schema({ name: String }, { collection: 'actor' });
*
* // or
*
* schema.set('collection', 'actor');
*
* // or
*
* var collectionName = 'actor'
* var M = mongoose.model('Actor', schema, collectionName)
*
* @param {String} name model name
* @param {Schema} [schema]
* @param {String} [collection] name (optional, induced from model name)
* @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
* @api public
*/
Mongoose.prototype.model = function (name, schema, collection, skipInit) {
if ('string' == typeof schema) {
collection = schema;
schema = false;
}
if (utils.isObject(schema) && !(schema instanceof Schema)) {
schema = new Schema(schema);
}
if ('boolean' === typeof collection) {
skipInit = collection;
collection = null;
}
// handle internal options from connection.model()
var options;
if (skipInit && utils.isObject(skipInit)) {
options = skipInit;
skipInit = true;
} else {
options = {};
}
// look up schema for the collection. this might be a
// default schema like system.indexes stored in SchemaDefaults.
if (!this.modelSchemas[name]) {
if (!schema && name in SchemaDefaults) {
schema = SchemaDefaults[name];
}
if (schema) {
// cache it so we only apply plugins once
this.modelSchemas[name] = schema;
this._applyPlugins(schema);
} else {
throw new mongoose.Error.MissingSchemaError(name);
}
}
var model;
var sub;
// connection.model() may be passing a different schema for
// an existing model name. in this case don't read from cache.
if (this.models[name] && false !== options.cache) {
if (schema instanceof Schema && schema != this.models[name].schema) {
throw new mongoose.Error.OverwriteModelError(name);
}
if (collection) {
// subclass current model with alternate collection
model = this.models[name];
schema = model.prototype.schema;
sub = model.__subclass(this.connection, schema, collection);
// do not cache the sub model
return sub;
}
return this.models[name];
}
// ensure a schema exists
if (!schema) {
schema = this.modelSchemas[name];
if (!schema) {
throw new mongoose.Error.MissingSchemaError(name);
}
}
if (!collection) {
collection = schema.get('collection') || format(name);
}
var connection = options.connection || this.connection;
model = Model.compile(name, schema, collection, connection, this);
if (!skipInit) {
model.init();
}
if (false === options.cache) {
return model;
}
return this.models[name] = model;
}
/**
* Returns an array of model names created on this instance of Mongoose.
*
* ####Note:
*
* _Does not include names of models created using `connection.model()`._
*
* @api public
* @return {Array}
*/
Mongoose.prototype.modelNames = function () {
var names = Object.keys(this.models);
return names;
}
/**
* Applies global plugins to `schema`.
*
* @param {Schema} schema
* @api private
*/
Mongoose.prototype._applyPlugins = function (schema) {
for (var i = 0, l = this.plugins.length; i < l; i++) {
schema.plugin(this.plugins[i][0], this.plugins[i][1]);
}
}
/**
* Declares a global plugin executed on all Schemas.
*
* Equivalent to calling `.plugin(fn)` on each Schema you create.
*
* @param {Function} fn plugin callback
* @param {Object} [opts] optional options
* @return {Mongoose} this
* @see plugins ./plugins.html
* @api public
*/
Mongoose.prototype.plugin = function (fn, opts) {
this.plugins.push([fn, opts]);
return this;
};
/**
* The default connection of the mongoose module.
*
* ####Example:
*
* var mongoose = require('mongoose');
* mongoose.connect(...);
* mongoose.connection.on('error', cb);
*
* This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
*
* @property connection
* @return {Connection}
* @api public
*/
Mongoose.prototype.__defineGetter__('connection', function(){
return this.connections[0];
});
/*!
* Driver depentend APIs
*/
var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
/*!
* Connection
*/
var Connection = require(driver + '/connection');
/*!
* Collection
*/
var Collection = require(driver + '/collection');
/**
* The Mongoose Collection constructor
*
* @method Collection
* @api public
*/
Mongoose.prototype.Collection = Collection;
/**
* The Mongoose [Connection](#connection_Connection) constructor
*
* @method Connection
* @api public
*/
Mongoose.prototype.Connection = Connection;
/**
* The Mongoose version
*
* @property version
* @api public
*/
Mongoose.prototype.version = require(__dirname + '/../package.json').version;
/**
* The Mongoose constructor
*
* The exports of the mongoose module is an instance of this class.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var mongoose2 = new mongoose.Mongoose();
*
* @method Mongoose
* @api public
*/
Mongoose.prototype.Mongoose = Mongoose;
/**
* The Mongoose [Schema](#schema_Schema) constructor
*
* ####Example:
*
* var mongoose = require('mongoose');
* var Schema = mongoose.Schema;
* var CatSchema = new Schema(..);
*
* @method Schema
* @api public
*/
Mongoose.prototype.Schema = Schema;
/**
* The Mongoose [SchemaType](#schematype_SchemaType) constructor
*
* @method SchemaType
* @api public
*/
Mongoose.prototype.SchemaType = SchemaType;
/**
* The various Mongoose SchemaTypes.
*
* ####Note:
*
* _Alias of mongoose.Schema.Types for backwards compatibility._
*
* @property SchemaTypes
* @see Schema.SchemaTypes #schema_Schema.Types
* @api public
*/
Mongoose.prototype.SchemaTypes = Schema.Types;
/**
* The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
*
* @method VirtualType
* @api public
*/
Mongoose.prototype.VirtualType = VirtualType;
/**
* The various Mongoose Types.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var array = mongoose.Types.Array;
*
* ####Types:
*
* - [ObjectId](#types-objectid-js)
* - [Buffer](#types-buffer-js)
* - [SubDocument](#types-embedded-js)
* - [Array](#types-array-js)
* - [DocumentArray](#types-documentarray-js)
*
* Using this exposed access to the `ObjectId` type, we can construct ids on demand.
*
* var ObjectId = mongoose.Types.ObjectId;
* var id1 = new ObjectId;
*
* @property Types
* @api public
*/
Mongoose.prototype.Types = Types;
/**
* The Mongoose [Query](#query_Query) constructor.
*
* @method Query
* @api public
*/
Mongoose.prototype.Query = Query;
/**
* The Mongoose [Promise](#promise_Promise) constructor.
*
* @method Promise
* @api public
*/
Mongoose.prototype.Promise = Promise;
/**
* The Mongoose [Model](#model_Model) constructor.
*
* @method Model
* @api public
*/
Mongoose.prototype.Model = Model;
/**
* The Mongoose [Document](#document-js) constructor.
*
* @method Document
* @api public
*/
Mongoose.prototype.Document = Document;
/**
* The [MongooseError](#error_MongooseError) constructor.
*
* @method Error
* @api public
*/
Mongoose.prototype.Error = require('./error');
/**
* The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.
*
* @property mongo
* @api public
*/
Mongoose.prototype.mongo = require('mongodb');
/*!
* The exports object is an instance of Mongoose.
*
* @api public
*/
var mongoose = module.exports = exports = new Mongoose;

31
node_modules/mongoose/lib/internal.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
/*!
* Dependencies
*/
var StateMachine = require('./statemachine')
var ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default')
module.exports = exports = InternalCache;
function InternalCache () {
this.strictMode = undefined;
this.selected = undefined;
this.shardval = undefined;
this.saveError = undefined;
this.validationError = undefined;
this.adhocPaths = undefined;
this.removing = undefined;
this.inserting = undefined;
this.version = undefined;
this.getters = {};
this._id = undefined;
this.populate = undefined; // what we want to populate in this doc
this.populated = undefined;// the _ids that have been populated
this.wasPopulated = false; // if this doc was the result of a population
this.scope = undefined;
this.activePaths = new ActiveRoster;
// embedded docs
this.ownerDocument = undefined;
this.fullPath = undefined;
}

2254
node_modules/mongoose/lib/model.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

70
node_modules/mongoose/lib/namedscope.js generated vendored Normal file
View File

@ -0,0 +1,70 @@
var Query = require('./query');
function NamedScope () {}
NamedScope.prototype.query;
NamedScope.prototype.where = function () {
var q = this.query || (this.query = new Query());
q.where.apply(q, arguments);
return q;
};
/**
* Decorate
*
* @param {NamedScope} target
* @param {Object} getters
* @api private
*/
NamedScope.prototype.decorate = function (target, getters) {
var name = this.name
, block = this.block
, query = this.query;
if (block) {
if (block.length === 0) {
Object.defineProperty(target, name, {
get: getters.block0(block)
});
} else {
target[name] = getters.blockN(block);
}
} else {
Object.defineProperty(target, name, {
get: getters.basic(query)
});
}
};
NamedScope.prototype.compile = function (model) {
var allScopes = this.scopesByName
, scope;
for (var k in allScopes) {
scope = allScopes[k];
scope.decorate(model, {
block0: function (block) {
return function () {
var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this));
block.call(cquery);
return this;
};
},
blockN: function (block) {
return function () {
var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this));
block.apply(cquery, arguments);
return this;
};
},
basic: function (query) {
return function () {
var cquery = this._cumulativeQuery || (this._cumulativeQuery = new Query().bind(this));
cquery.find(query);
return this;
};
}
});
}
};
module.exports = NamedScope;

231
node_modules/mongoose/lib/promise.js generated vendored Normal file
View File

@ -0,0 +1,231 @@
/*!
* Module dependencies
*/
var MPromise = require('mpromise');
/**
* Promise constructor.
*
* Promises are returned from executed queries. Example:
*
* var query = Candy.find({ bar: true });
* var promise = query.exec();
*
* @param {Function} fn a function which will be called when the promise is resolved that accepts `fn(err, ...){}` as signature
* @inherits mpromise https://github.com/aheckmann/mpromise
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `err`: Emits when the promise is rejected
* @event `complete`: Emits when the promise is fulfilled
* @api public
*/
function Promise (fn) {
MPromise.call(this, fn);
}
/*!
* Inherit from mpromise
*/
Promise.prototype = Object.create(MPromise.prototype, {
constructor: {
value: Promise
, enumerable: false
, writable: true
, configurable: true
}
});
/*!
* Override event names for backward compatibility.
*/
Promise.SUCCESS = 'complete';
Promise.FAILURE = 'err';
/**
* Adds `listener` to the `event`.
*
* If `event` is either the success or failure event and the event has already been emitted, the`listener` is called immediately and passed the results of the original emitted event.
*
* @see mpromise#on https://github.com/aheckmann/mpromise#on
* @method on
* @memberOf Promise
* @param {String} event
* @param {Function} listener
* @return {Promise} this
* @api public
*/
/**
* Rejects this promise with `reason`.
*
* If the promise has already been fulfilled or rejected, not action is taken.
*
* @see mpromise#reject https://github.com/aheckmann/mpromise#reject
* @method reject
* @memberOf Promise
* @param {Object|String|Error} reason
* @return {Promise} this
* @api public
*/
/**
* Rejects this promise with `err`.
*
* If the promise has already been fulfilled or rejected, not action is taken.
*
* Differs from [#reject](#promise_Promise-reject) by first casting `err` to an `Error` if it is not `instanceof Error`.
*
* @api public
* @param {Error|String} err
* @return {Promise} this
*/
Promise.prototype.error = function (err) {
if (!(err instanceof Error)) err = new Error(err);
return this.reject(err);
}
/**
* Resolves this promise to a rejected state if `err` is passed or a fulfilled state if no `err` is passed.
*
* If the promise has already been fulfilled or rejected, not action is taken.
*
* `err` will be cast to an Error if not already instanceof Error.
*
* _NOTE: overrides [mpromise#resolve](https://github.com/aheckmann/mpromise#resolve) to provide error casting._
*
* @param {Error} [err] error or null
* @param {Object} [val] value to fulfill the promise with
* @api public
*/
Promise.prototype.resolve = function (err, val) {
if (err) return this.error(err);
return this.fulfill(val);
}
/**
* Adds a single function as a listener to both err and complete.
*
* It will be executed with traditional node.js argument position when the promise is resolved.
*
* promise.addBack(function (err, args...) {
* if (err) return handleError(err);
* console.log('success');
* })
*
* Alias of [mpromise#onResolve](https://github.com/aheckmann/mpromise#onresolve).
*
* @method addBack
* @param {Function} listener
* @return {Promise} this
*/
Promise.prototype.addBack = Promise.prototype.onResolve;
/**
* Fulfills this promise with passed arguments.
*
* Alias of [mpromise#fulfill](https://github.com/aheckmann/mpromise#fulfill).
*
* @method complete
* @param {any} args
* @api public
*/
Promise.prototype.complete = MPromise.prototype.fulfill;
/**
* Adds a listener to the `complete` (success) event.
*
* Alias of [mpromise#onFulfill](https://github.com/aheckmann/mpromise#onfulfill).
*
* @method addCallback
* @param {Function} listener
* @return {Promise} this
* @api public
*/
Promise.prototype.addCallback = Promise.prototype.onFulfill;
/**
* Adds a listener to the `err` (rejected) event.
*
* Alias of [mpromise#onReject](https://github.com/aheckmann/mpromise#onreject).
*
* @method addErrback
* @param {Function} listener
* @return {Promise} this
* @api public
*/
Promise.prototype.addErrback = Promise.prototype.onReject;
/**
* Creates a new promise and returns it. If `onFulfill` or `onReject` are passed, they are added as SUCCESS/ERROR callbacks to this promise after the nextTick.
*
* Conforms to [promises/A+](https://github.com/promises-aplus/promises-spec) specification.
*
* ####Example:
*
* var promise = Meetups.find({ tags: 'javascript' }).select('_id').exec();
* promise.then(function (meetups) {
* var ids = meetups.map(function (m) {
* return m._id;
* });
* return People.find({ meetups: { $in: ids }).exec();
* }).then(function (people) {
* if (people.length < 10000) {
* throw new Error('Too few people!!!');
* } else {
* throw new Error('Still need more people!!!');
* }
* }).then(null, function (err) {
* assert.ok(err instanceof Error);
* });
*
* @see promises-A+ https://github.com/promises-aplus/promises-spec
* @see mpromise#then https://github.com/aheckmann/mpromise#then
* @method then
* @memberOf Promise
* @param {Function} onFulFill
* @param {Function} onReject
* @return {Promise} newPromise
*/
/**
* Signifies that this promise was the last in a chain of `then()s`: if a handler passed to the call to `then` which produced this promise throws, the exception will go uncaught.
*
* ####Example:
*
* var p = new Promise;
* p.then(function(){ throw new Error('shucks') });
* setTimeout(function () {
* p.fulfill();
* // error was caught and swallowed by the promise returned from
* // p.then(). we either have to always register handlers on
* // the returned promises or we can do the following...
* }, 10);
*
* // this time we use .end() which prevents catching thrown errors
* var p = new Promise;
* var p2 = p.then(function(){ throw new Error('shucks') }).end(); // <--
* setTimeout(function () {
* p.fulfill(); // throws "shucks"
* }, 10);
*
* @api public
* @see mpromise#end https://github.com/aheckmann/mpromise#end
* @method end
* @memberOf Promise
*/
/*!
* expose
*/
module.exports = Promise;

2612
node_modules/mongoose/lib/query.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

35
node_modules/mongoose/lib/queryhelpers.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
/*!
* Module dependencies
*/
var utils = require('./utils')
/*!
* Prepare a set of path options for query population.
*
* @param {Query} query
* @param {Object} options
* @return {Array}
*/
exports.preparePopulationOptions = function preparePopulationOptions (query, options) {
var pop = utils.object.vals(query.options.populate);
// lean options should trickle through all queries
if (options.lean) pop.forEach(makeLean);
return pop;
}
/*!
* Set each path query option to lean
*
* @param {Object} option
*/
function makeLean (option) {
option.options || (option.options = {});
option.options.lean = true;
}

336
node_modules/mongoose/lib/querystream.js generated vendored Normal file
View File

@ -0,0 +1,336 @@
/*!
* Module dependencies.
*/
var Stream = require('stream').Stream
var utils = require('./utils')
var helpers = require('./queryhelpers')
var K = function(k){ return k }
/**
* Provides a Node.js 0.8 style [ReadStream](http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream) interface for Queries.
*
* var stream = Model.find().stream();
*
* stream.on('data', function (doc) {
* // do something with the mongoose document
* }).on('error', function (err) {
* // handle the error
* }).on('close', function () {
* // the stream is closed
* });
*
*
* The stream interface allows us to simply "plug-in" to other _Node.js 0.8_ style write streams.
*
* Model.where('created').gte(twoWeeksAgo).stream().pipe(writeStream);
*
* ####Valid options
*
* - `transform`: optional function which accepts a mongoose document. The return value of the function will be emitted on `data`.
*
* ####Example
*
* // JSON.stringify all documents before emitting
* var stream = Thing.find().stream({ transform: JSON.stringify });
* stream.pipe(writeStream);
*
* _NOTE: plugging into an HTTP response will *not* work out of the box. Those streams expect only strings or buffers to be emitted, so first formatting our documents as strings/buffers is necessary._
*
* _NOTE: these streams are Node.js 0.8 style read streams which differ from Node.js 0.10 style. Node.js 0.10 streams are not well tested yet and are not guaranteed to work._
*
* @param {Query} query
* @param {Object} [options]
* @inherits NodeJS Stream http://nodejs.org/docs/v0.8.21/api/stream.html#stream_readable_stream
* @event `data`: emits a single Mongoose document
* @event `error`: emits when an error occurs during streaming. This will emit _before_ the `close` event.
* @event `close`: emits when the stream reaches the end of the cursor or an error occurs, or the stream is manually `destroy`ed. After this event, no more events are emitted.
* @api public
*/
function QueryStream (query, options) {
Stream.call(this);
this.query = query;
this.readable = true;
this.paused = false;
this._cursor = null;
this._destroyed = null;
this._fields = null;
this._buffer = null;
this._inline = T_INIT;
this._running = false;
this._transform = options && 'function' == typeof options.transform
? options.transform
: K;
// give time to hook up events
var self = this;
process.nextTick(function () {
self._init();
});
}
/*!
* Inherit from Stream
*/
QueryStream.prototype.__proto__ = Stream.prototype;
/**
* Flag stating whether or not this stream is readable.
*
* @property readable
* @api public
*/
QueryStream.prototype.readable;
/**
* Flag stating whether or not this stream is paused.
*
* @property paused
* @api public
*/
QueryStream.prototype.paused;
// trampoline flags
var T_INIT = 0;
var T_IDLE = 1;
var T_CONT = 2;
/**
* Initializes the query.
*
* @api private
*/
QueryStream.prototype._init = function () {
if (this._destroyed) return;
var query = this.query
, model = query.model
, options = query._optionsForExec(model)
, self = this
try {
query.cast(model);
} catch (err) {
return self.destroy(err);
}
self._fields = utils.clone(query._fields);
options.fields = query._castFields(self._fields);
model.collection.find(query._conditions, options, function (err, cursor) {
if (err) return self.destroy(err);
self._cursor = cursor;
self._next();
});
}
/**
* Trampoline for pulling the next doc from cursor.
*
* @see QueryStream#__next #querystream_QueryStream-__next
* @api private
*/
QueryStream.prototype._next = function _next () {
if (this.paused || this._destroyed) {
return this._running = false;
}
this._running = true;
if (this._buffer && this._buffer.length) {
var arg;
while (!this.paused && !this._destroyed && (arg = this._buffer.shift())) {
this._onNextObject.apply(this, arg);
}
}
// avoid stack overflows with large result sets.
// trampoline instead of recursion.
while (this.__next()) {}
}
/**
* Pulls the next doc from the cursor.
*
* @see QueryStream#_next #querystream_QueryStream-_next
* @api private
*/
QueryStream.prototype.__next = function () {
if (this.paused || this._destroyed)
return this._running = false;
var self = this;
self._inline = T_INIT;
self._cursor.nextObject(function cursorcb (err, doc) {
self._onNextObject(err, doc);
});
// if onNextObject() was already called in this tick
// return ourselves to the trampoline.
if (T_CONT === this._inline) {
return true;
} else {
// onNextObject() hasn't fired yet. tell onNextObject
// that its ok to call _next b/c we are not within
// the trampoline anymore.
this._inline = T_IDLE;
}
}
/**
* Transforms raw `doc`s returned from the cursor into a model instance.
*
* @param {Error|null} err
* @param {Object} doc
* @api private
*/
QueryStream.prototype._onNextObject = function _onNextObject (err, doc) {
if (this._destroyed) return;
if (this.paused) {
this._buffer || (this._buffer = []);
this._buffer.push([err, doc]);
return this._running = false;
}
if (err) return this.destroy(err);
// when doc is null we hit the end of the cursor
if (!doc) {
this.emit('end');
return this.destroy();
}
var opts = this.query.options;
if (!opts.populate) {
return true === opts.lean
? emit(this, doc)
: createAndEmit(this, doc);
}
var self = this;
var pop = helpers.preparePopulationOptions(self.query, self.query.options);
self.query.model.populate(doc, pop, function (err, doc) {
if (err) return self.destroy(err);
return true === opts.lean
? emit(self, doc)
: createAndEmit(self, doc);
})
}
function createAndEmit (self, doc) {
var instance = new self.query.model(undefined, self._fields, true);
instance.init(doc, function (err) {
if (err) return self.destroy(err);
emit(self, instance);
});
}
/*!
* Emit a data event and manage the trampoline state
*/
function emit (self, doc) {
self.emit('data', self._transform(doc));
// trampoline management
if (T_IDLE === self._inline) {
// no longer in trampoline. restart it.
self._next();
} else {
// in a trampoline. tell __next that its
// ok to continue jumping.
self._inline = T_CONT;
}
}
/**
* Pauses this stream.
*
* @api public
*/
QueryStream.prototype.pause = function () {
this.paused = true;
}
/**
* Resumes this stream.
*
* @api public
*/
QueryStream.prototype.resume = function () {
this.paused = false;
if (!this._cursor) {
// cannot start if not initialized
return;
}
// are we within the trampoline?
if (T_INIT === this._inline) {
return;
}
if (!this._running) {
// outside QueryStream control, need manual restart
return this._next();
}
}
/**
* Destroys the stream, closing the underlying cursor. No more events will be emitted.
*
* @param {Error} [err]
* @api public
*/
QueryStream.prototype.destroy = function (err) {
if (this._destroyed) return;
this._destroyed = true;
this._running = false;
this.readable = false;
if (this._cursor) {
this._cursor.close();
}
if (err) {
this.emit('error', err);
}
this.emit('close');
}
/**
* Pipes this query stream into another stream. This method is inherited from NodeJS Streams.
*
* ####Example:
*
* query.stream().pipe(writeStream [, options])
*
* @method pipe
* @memberOf QueryStream
* @see NodeJS http://nodejs.org/api/stream.html
* @api public
*/
/*!
* Module exports
*/
module.exports = exports = QueryStream;

910
node_modules/mongoose/lib/schema.js generated vendored Normal file
View File

@ -0,0 +1,910 @@
/*!
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter
, VirtualType = require('./virtualtype')
, utils = require('./utils')
, NamedScope
, Query
, Types
/**
* Schema constructor.
*
* ####Example:
*
* var child = new Schema({ name: String });
* var schema = new Schema({ name: String, age: Number, children: [child] });
* var Tree = mongoose.model('Tree', schema);
*
* // setting schema options
* new Schema({ name: String }, { _id: false, autoIndex: false })
*
* ####Options:
*
* - [autoIndex](/docs/guide.html#autoIndex): bool - defaults to true
* - [bufferCommands](/docs/guide.html#bufferCommands): bool - defaults to true
* - [capped](/docs/guide.html#capped): bool - defaults to false
* - [collection](/docs/guide.html#collection): string - no default
* - [id](/docs/guide.html#id): bool - defaults to true
* - [_id](/docs/guide.html#_id): bool - defaults to true
* - `minimize`: bool - controls [document#toObject](#document_Document-toObject) behavior when called manually - defaults to true
* - [read](/docs/guide.html#read): string
* - [safe](/docs/guide.html#safe): bool - defaults to true.
* - [shardKey](/docs/guide.html#shardKey): bool - defaults to `null`
* - [strict](/docs/guide.html#strict): bool - defaults to true
* - [toJSON](/docs/guide.html#toJSON) - object - no default
* - [toObject](/docs/guide.html#toObject) - object - no default
* - [versionKey](/docs/guide.html#versionKey): bool - defaults to "__v"
*
* ####Note:
*
* _When nesting schemas, (`children` in the example above), always declare the child schema first before passing it into is parent._
*
* @param {Object} definition
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `init`: Emitted after the schema is compiled into a `Model`.
* @api public
*/
function Schema (obj, options) {
if (!(this instanceof Schema))
return new Schema(obj, options);
this.paths = {};
this.subpaths = {};
this.virtuals = {};
this.nested = {};
this.inherits = {};
this.callQueue = [];
this._indexes = [];
this.methods = {};
this.statics = {};
this.tree = {};
this._requiredpaths = undefined;
this.options = this.defaultOptions(options);
// build paths
if (obj) {
this.add(obj);
}
// ensure the documents get an auto _id unless disabled
var auto_id = !this.paths['_id'] && (!this.options.noId && this.options._id);
if (auto_id) {
this.add({ _id: {type: Schema.ObjectId, auto: true} });
}
// ensure the documents receive an id getter unless disabled
var autoid = !this.paths['id'] && (!this.options.noVirtualId && this.options.id);
if (autoid) {
this.virtual('id').get(idGetter);
}
}
/*!
* Returns this documents _id cast to a string.
*/
function idGetter () {
if (this.$__._id) {
return this.$__._id;
}
return this.$__._id = null == this._id
? null
: String(this._id);
}
/*!
* Inherit from EventEmitter.
*/
Schema.prototype.__proto__ = EventEmitter.prototype;
/**
* Schema as flat paths
*
* ####Example:
* {
* '_id' : SchemaType,
* , 'nested.key' : SchemaType,
* }
*
* @api private
* @property paths
*/
Schema.prototype.paths;
/**
* Schema as a tree
*
* ####Example:
* {
* '_id' : ObjectId
* , 'nested' : {
* 'key' : String
* }
* }
*
* @api private
* @property tree
*/
Schema.prototype.tree;
/**
* Returns default options for this schema, merged with `options`.
*
* @param {Object} options
* @return {Object}
* @api private
*/
Schema.prototype.defaultOptions = function (options) {
if (options && false === options.safe) {
options.safe = { w: 0 };
}
options = utils.options({
strict: true
, bufferCommands: true
, capped: false // { size, max, autoIndexId }
, versionKey: '__v'
, minimize: true
, autoIndex: true
, shardKey: null
, read: null
// the following are only applied at construction time
, noId: false // deprecated, use { _id: false }
, _id: true
, noVirtualId: false // deprecated, use { id: false }
, id: true
}, options);
if (options.read)
options.read = utils.readPref(options.read);
return options;
}
/**
* Adds key path / schema type pairs to this schema.
*
* ####Example:
*
* var ToySchema = new Schema;
* ToySchema.add({ name: 'string', color: 'string', price: 'number' });
*
* @param {Object} obj
* @param {String} prefix
* @api public
*/
Schema.prototype.add = function add (obj, prefix) {
prefix = prefix || '';
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
if (null == obj[key]) {
throw new TypeError('Invalid value for schema path `'+ prefix + key +'`');
}
if (utils.isObject(obj[key]) && (!obj[key].constructor || 'Object' == obj[key].constructor.name) && (!obj[key].type || obj[key].type.type)) {
if (Object.keys(obj[key]).length) {
// nested object { last: { name: String }}
this.nested[prefix + key] = true;
this.add(obj[key], prefix + key + '.');
} else {
this.path(prefix + key, obj[key]); // mixed type
}
} else {
this.path(prefix + key, obj[key]);
}
}
};
/**
* Reserved document keys.
*
* Keys in this object are names that are rejected in schema declarations b/c they conflict with mongoose functionality. Using these key name will throw an error.
*
* on, emit, _events, db, init, isNew, errors, schema, options, modelName, collection, _pres, _posts, toObject
*
* _NOTE:_ Use of these terms as method names is permitted, but play at your own risk, as they may be existing mongoose document methods you are stomping on.
*
* var schema = new Schema(..);
* schema.methods.init = function () {} // potentially breaking
*/
Schema.reserved = Object.create(null);
var reserved = Schema.reserved;
reserved.on =
reserved.db =
reserved.init =
reserved.isNew =
reserved.errors =
reserved.schema =
reserved.options =
reserved.modelName =
reserved.collection =
reserved.toObject =
reserved.emit = // EventEmitter
reserved._events = // EventEmitter
reserved._pres = reserved._posts = 1 // hooks.js
/**
* Gets/sets schema paths.
*
* Sets a path (if arity 2)
* Gets a path (if arity 1)
*
* ####Example
*
* schema.path('name') // returns a SchemaType
* schema.path('name', Number) // changes the schemaType of `name` to Number
*
* @param {String} path
* @param {Object} constructor
* @api public
*/
Schema.prototype.path = function (path, obj) {
if (obj == undefined) {
if (this.paths[path]) return this.paths[path];
if (this.subpaths[path]) return this.subpaths[path];
// subpaths?
return /\.\d+\.?.*$/.test(path)
? getPositionalPath(this, path)
: undefined;
}
// some path names conflict with document methods
if (reserved[path]) {
throw new Error("`" + path + "` may not be used as a schema pathname");
}
// update the tree
var subpaths = path.split(/\./)
, last = subpaths.pop()
, branch = this.tree;
subpaths.forEach(function(sub, i) {
if (!branch[sub]) branch[sub] = {};
if ('object' != typeof branch[sub]) {
var msg = 'Cannot set nested path `' + path + '`. '
+ 'Parent path `'
+ subpaths.slice(0, i).concat([sub]).join('.')
+ '` already set to type ' + branch[sub].name
+ '.';
throw new Error(msg);
}
branch = branch[sub];
});
branch[last] = utils.clone(obj);
this.paths[path] = Schema.interpretAsType(path, obj);
return this;
};
/**
* Converts type arguments into Mongoose Types.
*
* @param {String} path
* @param {Object} obj constructor
* @api private
*/
Schema.interpretAsType = function (path, obj) {
if (obj.constructor && obj.constructor.name != 'Object')
obj = { type: obj };
// Get the type making sure to allow keys named "type"
// and default to mixed if not specified.
// { type: { type: String, default: 'freshcut' } }
var type = obj.type && !obj.type.type
? obj.type
: {};
if ('Object' == type.constructor.name || 'mixed' == type) {
return new Types.Mixed(path, obj);
}
if (Array.isArray(type) || Array == type || 'array' == type) {
// if it was specified through { type } look for `cast`
var cast = (Array == type || 'array' == type)
? obj.cast
: type[0];
if (cast instanceof Schema) {
return new Types.DocumentArray(path, cast, obj);
}
if ('string' == typeof cast) {
cast = Types[cast.charAt(0).toUpperCase() + cast.substring(1)];
} else if (cast && (!cast.type || cast.type.type)
&& 'Object' == cast.constructor.name
&& Object.keys(cast).length) {
return new Types.DocumentArray(path, new Schema(cast), obj);
}
return new Types.Array(path, cast || Types.Mixed, obj);
}
var name = 'string' == typeof type
? type
: type.name;
if (name) {
name = name.charAt(0).toUpperCase() + name.substring(1);
}
if (undefined == Types[name]) {
throw new TypeError('Undefined type at `' + path +
'`\n Did you try nesting Schemas? ' +
'You can only nest using refs or arrays.');
}
return new Types[name](path, obj);
};
/**
* Iterates the schemas paths similar to Array#forEach.
*
* The callback is passed the pathname and schemaType as arguments on each iteration.
*
* @param {Function} fn callback function
* @return {Schema} this
* @api public
*/
Schema.prototype.eachPath = function (fn) {
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;
};
/**
* Returns an Array of path strings that are required by this schema.
*
* @api public
* @return {Array}
*/
Schema.prototype.requiredPaths = function requiredPaths () {
if (this._requiredpaths) return this._requiredpaths;
var paths = Object.keys(this.paths)
, i = paths.length
, ret = [];
while (i--) {
var path = paths[i];
if (this.paths[path].isRequired) ret.push(path);
}
return this._requiredpaths = ret;
}
/**
* Returns the pathType of `path` for this schema.
*
* Given a path, returns whether it is a real, virtual, nested, or ad-hoc/undefined path.
*
* @param {String} path
* @return {String}
* @api public
*/
Schema.prototype.pathType = function (path) {
if (path in this.paths) return 'real';
if (path in this.virtuals) return 'virtual';
if (path in this.nested) return 'nested';
if (path in this.subpaths) return 'real';
if (/\.\d+\.|\.\d+$/.test(path) && getPositionalPath(this, path)) {
return 'real';
} else {
return 'adhocOrUndefined'
}
};
/*!
* ignore
*/
function getPositionalPath (self, path) {
var subpaths = path.split(/\.(\d+)\.|\.(\d+)$/).filter(Boolean);
if (subpaths.length < 2) {
return self.paths[subpaths[0]];
}
var val = self.path(subpaths[0]);
if (!val) return val;
var last = subpaths.length - 1
, subpath
, i = 1;
for (; i < subpaths.length; ++i) {
subpath = subpaths[i];
if (i === last && val && !val.schema && !/\D/.test(subpath)) {
if (val instanceof Types.Array) {
// StringSchema, NumberSchema, etc
val = val.caster;
} else {
val = undefined;
}
break;
}
// ignore if its just a position segment: path.0.subpath
if (!/\D/.test(subpath)) continue;
if (!(val && val.schema)) {
val = undefined;
break;
}
val = val.schema.path(subpath);
}
return self.subpaths[path] = val;
}
/**
* Adds a method call to the queue.
*
* @param {String} name name of the document method to call later
* @param {Array} args arguments to pass to the method
* @api private
*/
Schema.prototype.queue = function(name, args){
this.callQueue.push([name, args]);
return this;
};
/**
* Defines a pre hook for the document.
*
* ####Example
*
* var toySchema = new Schema(..);
*
* toySchema.pre('save', function (next) {
* if (!this.created) this.created = new Date;
* next();
* })
*
* toySchema.pre('validate', function (next) {
* if (this.name != 'Woody') this.name = 'Woody';
* next();
* })
*
* @param {String} method
* @param {Function} callback
* @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3
* @api public
*/
Schema.prototype.pre = function(){
return this.queue('pre', arguments);
};
/**
* Defines a post for the document
*
* Post hooks fire `on` the event emitted from document instances of Models compiled from this schema.
*
* var schema = new Schema(..);
* schema.post('save', function (doc) {
* console.log('this fired after a document was saved');
* });
*
* var Model = mongoose.model('Model', schema);
*
* var m = new Model(..);
* m.save(function (err) {
* console.log('this fires after the `post` hook');
* });
*
* @param {String} method name of the method to hook
* @param {Function} fn callback
* @see hooks.js https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3
* @api public
*/
Schema.prototype.post = function(method, fn){
return this.queue('on', arguments);
};
/**
* Registers a plugin for this schema.
*
* @param {Function} plugin callback
* @param {Object} opts
* @see plugins
* @api public
*/
Schema.prototype.plugin = function (fn, opts) {
fn(this, opts);
return this;
};
/**
* Adds an instance method to documents constructed from Models compiled from this schema.
*
* ####Example
*
* var schema = kittySchema = new Schema(..);
*
* schema.method('meow', function () {
* console.log('meeeeeoooooooooooow');
* })
*
* var Kitty = mongoose.model('Kitty', schema);
*
* var fizz = new Kitty;
* fizz.meow(); // meeeeeooooooooooooow
*
* If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as methods.
*
* schema.method({
* purr: function () {}
* , scratch: function () {}
* });
*
* // later
* fizz.purr();
* fizz.scratch();
*
* @param {String|Object} method name
* @param {Function} [fn]
* @api public
*/
Schema.prototype.method = function (name, fn) {
if ('string' != typeof name)
for (var i in name)
this.methods[i] = name[i];
else
this.methods[name] = fn;
return this;
};
/**
* Adds static "class" methods to Models compiled from this schema.
*
* ####Example
*
* var schema = new Schema(..);
* schema.static('findByName', function (name, callback) {
* return this.find({ name: name }, callback);
* });
*
* var Drink = mongoose.model('Drink', schema);
* Drink.findByName('sanpellegrino', function (err, drinks) {
* //
* });
*
* If a hash of name/fn pairs is passed as the only argument, each name/fn pair will be added as statics.
*
* @param {String} name
* @param {Function} fn
* @api public
*/
Schema.prototype.static = function(name, fn) {
if ('string' != typeof name)
for (var i in name)
this.statics[i] = name[i];
else
this.statics[name] = fn;
return this;
};
/**
* Defines an index (most likely compound) for this schema.
*
* ####Example
*
* schema.index({ first: 1, last: -1 })
*
* @param {Object} fields
* @param {Object} [options]
* @api public
*/
Schema.prototype.index = function (fields, options) {
options || (options = {});
if (options.expires)
utils.expires(options);
this._indexes.push([fields, options]);
return this;
};
/**
* Sets/gets a schema option.
*
* @param {String} key option name
* @param {Object} [value] if not passed, the current option value is returned
* @api public
*/
Schema.prototype.set = function (key, value, _tags) {
if (1 === arguments.length) {
return this.options[key];
}
switch (key) {
case 'read':
this.options[key] = utils.readPref(value, _tags)
break;
case 'safe':
this.options[key] = false === value
? { w: 0 }
: value
break;
default:
this.options[key] = value;
}
return this;
}
/**
* Gets a schema option.
*
* @param {String} key option name
* @api public
*/
Schema.prototype.get = function (key) {
return this.options[key];
}
/**
* The allowed index types
*
* @static indexTypes
* @receiver Schema
* @api public
*/
var indexTypes = '2d 2dsphere hashed text'.split(' ');
Object.defineProperty(Schema, 'indexTypes', {
get: function () { return indexTypes }
, set: function () { throw new Error('Cannot overwrite Schema.indexTypes') }
})
/**
* Compiles indexes from fields and schema-level indexes
*
* @api public
*/
Schema.prototype.indexes = function () {
'use strict';
var indexes = []
, seenSchemas = []
collectIndexes(this);
return indexes;
function collectIndexes (schema, prefix) {
if (~seenSchemas.indexOf(schema)) return;
seenSchemas.push(schema);
prefix = prefix || '';
var key, path, index, field, isObject, options, type;
var keys = Object.keys(schema.paths);
for (var i = 0; i < keys.length; ++i) {
key = keys[i];
path = schema.paths[key];
if (path instanceof Types.DocumentArray) {
collectIndexes(path.schema, key + '.');
} else {
index = path._index;
if (false !== index && null != index) {
field = {};
isObject = utils.isObject(index);
options = isObject ? index : {};
type = 'string' == typeof index ? index :
isObject ? index.type :
false;
if (type && ~Schema.indexTypes.indexOf(type)) {
field[prefix + key] = type;
} else {
field[prefix + key] = 1;
}
delete options.type;
if (!('background' in options)) {
options.background = true;
}
indexes.push([field, options]);
}
}
}
if (prefix) {
fixSubIndexPaths(schema, prefix);
} else {
schema._indexes.forEach(function (index) {
if (!('background' in index[1])) index[1].background = true;
});
indexes = indexes.concat(schema._indexes);
}
}
/*!
* Checks for indexes added to subdocs using Schema.index().
* These indexes need their paths prefixed properly.
*
* schema._indexes = [ [indexObj, options], [indexObj, options] ..]
*/
function fixSubIndexPaths (schema, prefix) {
var subindexes = schema._indexes
, len = subindexes.length
, indexObj
, newindex
, klen
, keys
, key
, i = 0
, j
for (i = 0; i < len; ++i) {
indexObj = subindexes[i][0];
keys = Object.keys(indexObj);
klen = keys.length;
newindex = {};
// use forward iteration, order matters
for (j = 0; j < klen; ++j) {
key = keys[j];
newindex[prefix + key] = indexObj[key];
}
indexes.push([newindex, subindexes[i][1]]);
}
}
}
/**
* Creates a virtual type with the given name.
*
* @param {String} name
* @param {Object} [options]
* @return {VirtualType}
*/
Schema.prototype.virtual = function (name, options) {
var virtuals = this.virtuals;
var parts = name.split('.');
return virtuals[name] = parts.reduce(function (mem, part, i) {
mem[part] || (mem[part] = (i === parts.length-1)
? new VirtualType(options, name)
: {});
return mem[part];
}, this.tree);
};
/**
* Returns the virtual type with the given `name`.
*
* @param {String} name
* @return {VirtualType}
*/
Schema.prototype.virtualpath = function (name) {
return this.virtuals[name];
};
/**
* These still haven't been fixed. Once they're working we'll make them public again.
* @api private
*/
Schema.prototype.namedScope = function (name, fn) {
var namedScopes = this.namedScopes || (this.namedScopes = new NamedScope)
, newScope = Object.create(namedScopes)
, allScopes = namedScopes.scopesByName || (namedScopes.scopesByName = {});
allScopes[name] = newScope;
newScope.name = name;
newScope.block = fn;
newScope.query = new Query();
newScope.decorate(namedScopes, {
block0: function (block) {
return function () {
block.call(this.query);
return this;
};
},
blockN: function (block) {
return function () {
block.apply(this.query, arguments);
return this;
};
},
basic: function (query) {
return function () {
this.query.find(query);
return this;
};
}
});
return newScope;
};
/*!
* Module exports.
*/
module.exports = exports = Schema;
// require down here because of reference issues
/**
* The various built-in Mongoose Schema Types.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var ObjectId = mongoose.Schema.Types.ObjectId;
*
* ####Types:
*
* - [String](#schema-string-js)
* - [Number](#schema-number-js)
* - [Boolean](#schema-boolean-js) | Bool
* - [Array](#schema-array-js)
* - [Buffer](#schema-buffer-js)
* - [Date](#schema-date-js)
* - [ObjectId](#schema-objectid-js) | Oid
* - [Mixed](#schema-mixed-js)
*
* Using this exposed access to the `Mixed` SchemaType, we can use them in our schema.
*
* var Mixed = mongoose.Schema.Types.Mixed;
* new mongoose.Schema({ _user: Mixed })
*
* @api public
*/
Schema.Types = require('./schema/index');
/*!
* ignore
*/
Types = Schema.Types;
NamedScope = require('./namedscope')
Query = require('./query');
var ObjectId = exports.ObjectId = Types.ObjectId;

316
node_modules/mongoose/lib/schema/array.js generated vendored Normal file
View File

@ -0,0 +1,316 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, NumberSchema = require('./number')
, Types = {
Boolean: require('./boolean')
, Date: require('./date')
, Number: require('./number')
, String: require('./string')
, ObjectId: require('./objectid')
, Buffer: require('./buffer')
}
, MongooseArray = require('../types').Array
, EmbeddedDoc = require('../types').Embedded
, Mixed = require('./mixed')
, Query = require('../query')
, utils = require('../utils')
, isMongooseObject = utils.isMongooseObject
/**
* Array SchemaType constructor
*
* @param {String} key
* @param {SchemaType} cast
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function SchemaArray (key, cast, options) {
if (cast) {
var castOptions = {};
if ('Object' === cast.constructor.name) {
if (cast.type) {
// support { type: Woot }
castOptions = utils.clone(cast); // do not alter user arguments
delete castOptions.type;
cast = cast.type;
} else {
cast = Mixed;
}
}
// support { type: 'String' }
var name = 'string' == typeof cast
? cast
: cast.name;
var caster = name in Types
? Types[name]
: cast;
this.casterConstructor = caster;
this.caster = new caster(null, castOptions);
if (!(this.caster instanceof EmbeddedDoc)) {
this.caster.path = key;
}
}
SchemaType.call(this, key, options);
var self = this
, defaultArr
, fn;
if (this.defaultValue) {
defaultArr = this.defaultValue;
fn = 'function' == typeof defaultArr;
}
this.default(function(){
var arr = fn ? defaultArr() : defaultArr || [];
return new MongooseArray(arr, self.path, this);
});
};
/*!
* Inherits from SchemaType.
*/
SchemaArray.prototype.__proto__ = SchemaType.prototype;
/**
* Check required
*
* @param {Array} value
* @api private
*/
SchemaArray.prototype.checkRequired = function (value) {
return !!(value && value.length);
};
/**
* Overrides the getters application for the population special-case
*
* @param {Object} value
* @param {Object} scope
* @api private
*/
SchemaArray.prototype.applyGetters = function (value, scope) {
if (this.caster.options && this.caster.options.ref) {
// means the object id was populated
return value;
}
return SchemaType.prototype.applyGetters.call(this, value, scope);
};
/**
* Casts contents
*
* @param {Object} value
* @param {Document} doc document that triggers the casting
* @param {Boolean} init whether this is an initialization cast
* @api private
*/
SchemaArray.prototype.cast = function (value, doc, init) {
if (Array.isArray(value)) {
if (!(value instanceof MongooseArray)) {
value = new MongooseArray(value, this.path, doc);
}
if (this.caster) {
try {
for (var i = 0, l = value.length; i < l; i++) {
value[i] = this.caster.cast(value[i], doc, init);
}
} catch (e) {
// rethrow
throw new CastError(e.type, value, this.path);
}
}
return value;
} else {
return this.cast([value], doc, init);
}
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [value]
* @api private
*/
SchemaArray.prototype.castForQuery = function ($conditional, value) {
var handler
, val;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler)
throw new Error("Can't use " + $conditional + " with Array.");
val = handler.call(this, value);
} else {
val = $conditional;
var proto = this.casterConstructor.prototype;
var method = proto.castForQuery || proto.cast;
var caster = this.caster;
if (Array.isArray(val)) {
val = val.map(function (v) {
if (method) v = method.call(caster, v);
return isMongooseObject(v)
? v.toObject()
: v;
});
} else if (method) {
val = method.call(caster, val);
}
}
return val && isMongooseObject(val)
? val.toObject()
: val;
};
/*!
* @ignore
*/
function castToNumber (val) {
return Types.Number.prototype.cast.call(this, val);
}
function castArray (arr, self) {
self || (self = this);
arr.forEach(function (v, i) {
if (Array.isArray(v)) {
castArray(v, self);
} else {
arr[i] = castToNumber.call(self, v);
}
});
}
SchemaArray.prototype.$conditionalHandlers = {
'$all': function handle$all (val) {
if (!Array.isArray(val)) {
val = [val];
}
val = val.map(function (v) {
if (v && 'Object' === v.constructor.name) {
var o = {};
o[this.path] = v;
var query = new Query(o);
query.cast(this.casterConstructor);
return query._conditions[this.path];
}
return v;
}, this);
return this.castForQuery(val);
}
, '$elemMatch': function (val) {
if (val.$in) {
val.$in = this.castForQuery('$in', val.$in);
return val;
}
var query = new Query(val);
query.cast(this.casterConstructor);
return query._conditions;
}
, '$size': castToNumber
, '$ne': SchemaArray.prototype.castForQuery
, '$in': SchemaArray.prototype.castForQuery
, '$nin': SchemaArray.prototype.castForQuery
, '$regex': SchemaArray.prototype.castForQuery
, '$options': String
, '$near': SchemaArray.prototype.castForQuery
, '$nearSphere': SchemaArray.prototype.castForQuery
, '$gt': SchemaArray.prototype.castForQuery
, '$gte': SchemaArray.prototype.castForQuery
, '$lt': SchemaArray.prototype.castForQuery
, '$lte': SchemaArray.prototype.castForQuery
, '$within': function (val) {
var self = this;
if (val.$maxDistance) {
val.$maxDistance = castToNumber.call(this, val.$maxDistance);
}
if (val.$box || val.$polygon) {
var type = val.$box ? '$box' : '$polygon';
val[type].forEach(function (arr) {
if (!Array.isArray(arr)) {
var msg = 'Invalid $within $box argument. '
+ 'Expected an array, received ' + arr;
throw new TypeError(msg);
}
arr.forEach(function (v, i) {
arr[i] = castToNumber.call(this, v);
});
})
} else if (val.$center || val.$centerSphere) {
var type = val.$center ? '$center' : '$centerSphere';
val[type].forEach(function (item, i) {
if (Array.isArray(item)) {
item.forEach(function (v, j) {
item[j] = castToNumber.call(this, v);
});
} else {
val[type][i] = castToNumber.call(this, item);
}
})
} else if (val.$geometry) {
switch (val.$geometry.type) {
case 'Polygon':
case 'LineString':
case 'Point':
val.$geometry.coordinates.forEach(castArray);
break;
default:
// ignore unknowns
break;
}
}
return val;
}
, '$geoIntersects': function (val) {
var geo = val.$geometry;
if (!geo) return;
switch (val.$geometry.type) {
case 'Polygon':
case 'LineString':
case 'Point':
val.$geometry.coordinates.forEach(castArray);
break;
default:
// ignore unknowns
break;
}
return val;
}
, '$maxDistance': castToNumber
};
/*!
* Module exports.
*/
module.exports = SchemaArray;

92
node_modules/mongoose/lib/schema/boolean.js generated vendored Normal file
View File

@ -0,0 +1,92 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype');
/**
* Boolean SchemaType constructor.
*
* @param {String} path
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function SchemaBoolean (path, options) {
SchemaType.call(this, path, options);
};
/*!
* Inherits from SchemaType.
*/
SchemaBoolean.prototype.__proto__ = SchemaType.prototype;
/**
* Required validator
*
* @api private
*/
SchemaBoolean.prototype.checkRequired = function (value) {
return value === true || value === false;
};
/**
* Casts to boolean
*
* @param {Object} value
* @api private
*/
SchemaBoolean.prototype.cast = function (value) {
if (null === value) return value;
if ('0' === value) return false;
if ('true' === value) return true;
if ('false' === value) return false;
return !! value;
}
/*!
* ignore
*/
function handleArray (val) {
var self = this;
return val.map(function (m) {
return self.cast(m);
});
}
SchemaBoolean.$conditionalHandlers = {
'$in': handleArray
}
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} val
* @api private
*/
SchemaBoolean.prototype.castForQuery = function ($conditional, val) {
var handler;
if (2 === arguments.length) {
handler = SchemaBoolean.$conditionalHandlers[$conditional];
if (handler) {
return handler.call(this, val);
}
return this.cast(val);
}
return this.cast($conditional);
};
/*!
* Module exports.
*/
module.exports = SchemaBoolean;

168
node_modules/mongoose/lib/schema/buffer.js generated vendored Normal file
View File

@ -0,0 +1,168 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, MongooseBuffer = require('../types').Buffer
, Binary = MongooseBuffer.Binary
, Query = require('../query')
, utils = require('../utils')
, Document
/**
* Buffer SchemaType constructor
*
* @param {String} key
* @param {SchemaType} cast
* @inherits SchemaType
* @api private
*/
function SchemaBuffer (key, options) {
SchemaType.call(this, key, options, 'Buffer');
};
/*!
* Inherits from SchemaType.
*/
SchemaBuffer.prototype.__proto__ = SchemaType.prototype;
/**
* Check required
*
* @api private
*/
SchemaBuffer.prototype.checkRequired = function (value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return null != value;
} else {
return !!(value && value.length);
}
};
/**
* Casts contents
*
* @param {Object} value
* @param {Document} doc document that triggers the casting
* @param {Boolean} init
* @api private
*/
SchemaBuffer.prototype.cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (null == value) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (Buffer.isBuffer(value)) {
return value;
} else if (!utils.isObject(value)) {
throw new CastError('buffer', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
// documents
if (value && value._id) {
value = value._id;
}
if (Buffer.isBuffer(value)) {
if (!(value instanceof MongooseBuffer)) {
value = new MongooseBuffer(value, [this.path, doc]);
}
return value;
} else if (value instanceof Binary) {
var ret = new MongooseBuffer(value.value(true), [this.path, doc]);
ret._subtype = value.sub_type;
// do not override Binary subtypes. users set this
// to whatever they want.
return ret;
}
if (null === value) return value;
var type = typeof value;
if ('string' == type || 'number' == type || Array.isArray(value)) {
var ret = new MongooseBuffer(value, [this.path, doc]);
return ret;
}
throw new CastError('buffer', value, this.path);
};
/*!
* ignore
*/
function handleSingle (val) {
return this.castForQuery(val);
}
function handleArray (val) {
var self = this;
return val.map( function (m) {
return self.castForQuery(m);
});
}
SchemaBuffer.prototype.$conditionalHandlers = {
'$ne' : handleSingle
, '$in' : handleArray
, '$nin': handleArray
, '$gt' : handleSingle
, '$lt' : handleSingle
, '$gte': handleSingle
, '$lte': handleSingle
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [value]
* @api private
*/
SchemaBuffer.prototype.castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler)
throw new Error("Can't use " + $conditional + " with Buffer.");
return handler.call(this, val);
} else {
val = $conditional;
return this.cast(val).toObject();
}
};
/*!
* Module exports.
*/
module.exports = SchemaBuffer;

167
node_modules/mongoose/lib/schema/date.js generated vendored Normal file
View File

@ -0,0 +1,167 @@
/*!
* Module requirements.
*/
var SchemaType = require('../schematype');
var CastError = SchemaType.CastError;
var utils = require('../utils');
/**
* Date SchemaType constructor.
*
* @param {String} key
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function SchemaDate (key, options) {
SchemaType.call(this, key, options);
};
/*!
* Inherits from SchemaType.
*/
SchemaDate.prototype.__proto__ = SchemaType.prototype;
/**
* Declares a TTL index (rounded to the nearest second) for _Date_ types only.
*
* This sets the `expiresAfterSeconds` index option available in MongoDB >= 2.1.2.
* This index type is only compatible with Date types.
*
* ####Example:
*
* // expire in 24 hours
* new Schema({ createdAt: { type: Date, expires: 60*60*24 }});
*
* `expires` utilizes the `ms` module from [guille](https://github.com/guille/) allowing us to use a friendlier syntax:
*
* ####Example:
*
* // expire in 24 hours
* new Schema({ createdAt: { type: Date, expires: '24h' }});
*
* // expire in 1.5 hours
* new Schema({ createdAt: { type: Date, expires: '1.5h' }});
*
* // expire in 7 days
* var schema = new Schema({ createdAt: Date });
* schema.path('createdAt').expires('7d');
*
* @param {Number|String} when
* @added 3.0.0
* @return {SchemaType} this
* @api public
*/
SchemaDate.prototype.expires = function (when) {
if (!this._index || 'Object' !== this._index.constructor.name) {
this._index = {};
}
this._index.expires = when;
utils.expires(this._index);
return this;
};
/**
* Required validator for date
*
* @api private
*/
SchemaDate.prototype.checkRequired = function (value) {
return value instanceof Date;
};
/**
* Casts to date
*
* @param {Object} value to cast
* @api private
*/
SchemaDate.prototype.cast = function (value) {
if (value === null || value === '')
return null;
if (value instanceof Date)
return value;
var date;
// support for timestamps
if (value instanceof Number || 'number' == typeof value
|| String(value) == Number(value))
date = new Date(Number(value));
// support for date strings
else if (value.toString)
date = new Date(value.toString());
if (date.toString() != 'Invalid Date')
return date;
throw new CastError('date', value, this.path);
};
/*!
* Date Query casting.
*
* @api private
*/
function handleSingle (val) {
return this.cast(val);
}
function handleArray (val) {
var self = this;
return val.map( function (m) {
return self.cast(m);
});
}
SchemaDate.prototype.$conditionalHandlers = {
'$lt': handleSingle
, '$lte': handleSingle
, '$gt': handleSingle
, '$gte': handleSingle
, '$ne': handleSingle
, '$in': handleArray
, '$nin': handleArray
, '$all': handleArray
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [value]
* @api private
*/
SchemaDate.prototype.castForQuery = function ($conditional, val) {
var handler;
if (2 !== arguments.length) {
return this.cast($conditional);
}
handler = this.$conditionalHandlers[$conditional];
if (!handler) {
throw new Error("Can't use " + $conditional + " with Date.");
}
return handler.call(this, val);
};
/*!
* Module exports.
*/
module.exports = SchemaDate;

189
node_modules/mongoose/lib/schema/documentarray.js generated vendored Normal file
View File

@ -0,0 +1,189 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype')
, ArrayType = require('./array')
, MongooseDocumentArray = require('../types/documentarray')
, Subdocument = require('../types/embedded')
, Document = require('../document');
/**
* SubdocsArray SchemaType constructor
*
* @param {String} key
* @param {Schema} schema
* @param {Object} options
* @inherits SchemaArray
* @api private
*/
function DocumentArray (key, schema, options) {
// compile an embedded document for this schema
function EmbeddedDocument () {
Subdocument.apply(this, arguments);
}
EmbeddedDocument.prototype.__proto__ = Subdocument.prototype;
EmbeddedDocument.prototype.$__setSchema(schema);
EmbeddedDocument.schema = schema;
// apply methods
for (var i in schema.methods) {
EmbeddedDocument.prototype[i] = schema.methods[i];
}
// apply statics
for (var i in schema.statics)
EmbeddedDocument[i] = schema.statics[i];
EmbeddedDocument.options = options;
this.schema = schema;
ArrayType.call(this, key, EmbeddedDocument, options);
this.schema = schema;
var path = this.path;
var fn = this.defaultValue;
this.default(function(){
var arr = fn.call(this);
if (!Array.isArray(arr)) arr = [arr];
return new MongooseDocumentArray(arr, path, this);
});
};
/*!
* Inherits from ArrayType.
*/
DocumentArray.prototype.__proto__ = ArrayType.prototype;
/**
* Performs local validations first, then validations on each embedded doc
*
* @api private
*/
DocumentArray.prototype.doValidate = function (array, fn, scope) {
var self = this;
SchemaType.prototype.doValidate.call(this, array, function (err) {
if (err) return fn(err);
var count = array && array.length
, error;
if (!count) return fn();
// handle sparse arrays, do not use array.forEach which does not
// iterate over sparse elements yet reports array.length including
// them :(
for (var i = 0, len = count; i < len; ++i) {
// sidestep sparse entries
var doc = array[i];
if (!doc) {
--count || fn();
continue;
}
;(function (i) {
doc.validate(function (err) {
if (err && !error) {
// rewrite the key
err.key = self.key + '.' + i + '.' + err.key;
return fn(error = err);
}
--count || fn();
});
})(i);
}
}, scope);
};
/**
* Casts contents
*
* @param {Object} value
* @param {Document} document that triggers the casting
* @api private
*/
DocumentArray.prototype.cast = function (value, doc, init, prev) {
var selected
, subdoc
, i
if (!Array.isArray(value)) {
return this.cast([value], doc, init, prev);
}
if (!(value instanceof MongooseDocumentArray)) {
value = new MongooseDocumentArray(value, this.path, doc);
}
i = value.length;
while (i--) {
if (!(value[i] instanceof Subdocument) && value[i]) {
if (init) {
selected || (selected = scopePaths(this, doc.$__.selected, init));
subdoc = new this.casterConstructor(null, value, true, selected);
value[i] = subdoc.init(value[i]);
} else {
if (prev && (subdoc = prev.id(value[i]._id))) {
// handle resetting doc with existing id but differing data
// doc.array = [{ doc: 'val' }]
subdoc.set(value[i]);
} else {
subdoc = new this.casterConstructor(value[i], value);
}
// if set() is hooked it will have no return value
// see gh-746
value[i] = subdoc;
}
}
}
return value;
}
/*!
* Scopes paths selected in a query to this array.
* Necessary for proper default application of subdocument values.
*
* @param {DocumentArray} array - the array to scope `fields` paths
* @param {Object|undefined} fields - the root fields selected in the query
* @param {Boolean|undefined} init - if we are being created part of a query result
*/
function scopePaths (array, fields, init) {
if (!(init && fields)) return undefined;
var path = array.path + '.'
, keys = Object.keys(fields)
, i = keys.length
, selected = {}
, hasKeys
, key
while (i--) {
key = keys[i];
if (0 === key.indexOf(path)) {
hasKeys || (hasKeys = true);
selected[key.substring(path.length)] = fields[key];
}
}
return hasKeys && selected || undefined;
}
/*!
* Module exports.
*/
module.exports = DocumentArray;

28
node_modules/mongoose/lib/schema/index.js generated vendored Normal file
View File

@ -0,0 +1,28 @@
/*!
* Module exports.
*/
exports.String = require('./string');
exports.Number = require('./number');
exports.Boolean = require('./boolean');
exports.DocumentArray = require('./documentarray');
exports.Array = require('./array');
exports.Buffer = require('./buffer');
exports.Date = require('./date');
exports.ObjectId = require('./objectid');
exports.Mixed = require('./mixed');
// alias
exports.Oid = exports.ObjectId;
exports.Object = exports.Mixed;
exports.Bool = exports.Boolean;

83
node_modules/mongoose/lib/schema/mixed.js generated vendored Normal file
View File

@ -0,0 +1,83 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype');
var utils = require('../utils');
/**
* Mixed SchemaType constructor.
*
* @param {String} path
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function Mixed (path, options) {
if (options && options.default) {
var def = options.default;
if (Array.isArray(def) && 0 === def.length) {
// make sure empty array defaults are handled
options.default = Array;
} else if (!options.shared &&
utils.isObject(def) &&
0 === Object.keys(def).length) {
// prevent odd "shared" objects between documents
options.default = function () {
return {}
}
}
}
SchemaType.call(this, path, options);
};
/*!
* Inherits from SchemaType.
*/
Mixed.prototype.__proto__ = SchemaType.prototype;
/**
* Required validator
*
* @api private
*/
Mixed.prototype.checkRequired = function (val) {
return true;
};
/**
* Casts `val` for Mixed.
*
* _this is a no-op_
*
* @param {Object} value to cast
* @api private
*/
Mixed.prototype.cast = function (val) {
return val;
};
/**
* Casts contents for queries.
*
* @param {String} $cond
* @param {any} [val]
* @api private
*/
Mixed.prototype.castForQuery = function ($cond, val) {
if (arguments.length === 2) return val;
return $cond;
};
/*!
* Module exports.
*/
module.exports = Mixed;

227
node_modules/mongoose/lib/schema/number.js generated vendored Normal file
View File

@ -0,0 +1,227 @@
/*!
* Module requirements.
*/
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, utils = require('../utils')
, Document
/**
* Number SchemaType constructor.
*
* @param {String} key
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function SchemaNumber (key, options) {
SchemaType.call(this, key, options, 'Number');
};
/*!
* Inherits from SchemaType.
*/
SchemaNumber.prototype.__proto__ = SchemaType.prototype;
/**
* Required validator for number
*
* @api private
*/
SchemaNumber.prototype.checkRequired = function checkRequired (value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return null != value;
} else {
return typeof value == 'number' || value instanceof Number;
}
};
/**
* Sets a minimum number validator.
*
* ####Example:
*
* var s = new Schema({ n: { type: Number, min: 10 })
* var M = db.model('M', s)
* var m = new M({ n: 9 })
* m.save(function (err) {
* console.error(err) // validator error
* m.n = 10;
* m.save() // success
* })
*
* @param {Number} value minimum number
* @return {SchemaType} this
* @api public
*/
SchemaNumber.prototype.min = function (value) {
if (this.minValidator) {
this.validators = this.validators.filter(function (v) {
return 'min' != v[1];
});
}
if (value != null) {
this.validators.push([this.minValidator = function (v) {
return v === null || v >= value;
}, 'min']);
}
return this;
};
/**
* Sets a maximum number validator.
*
* ####Example:
*
* var s = new Schema({ n: { type: Number, max: 10 })
* var M = db.model('M', s)
* var m = new M({ n: 11 })
* m.save(function (err) {
* console.error(err) // validator error
* m.n = 10;
* m.save() // success
* })
*
* @param {Number} maximum number
* @return {SchemaType} this
* @api public
*/
SchemaNumber.prototype.max = function (value) {
if (this.maxValidator) {
this.validators = this.validators.filter(function(v){
return 'max' != v[1];
});
}
if (value != null) {
this.validators.push([this.maxValidator = function(v){
return v === null || v <= value;
}, 'max']);
}
return this;
};
/**
* Casts to number
*
* @param {Object} value value to cast
* @param {Document} doc document that triggers the casting
* @param {Boolean} init
* @api private
*/
SchemaNumber.prototype.cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (null == value) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if ('number' == typeof value) {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('number', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
var val = value && value._id
? value._id // documents
: value;
if (!isNaN(val)){
if (null === val) return val;
if ('' === val) return null;
if ('string' == typeof val) val = Number(val);
if (val instanceof Number) return val
if ('number' == typeof val) return val;
if (val.toString && !Array.isArray(val) &&
val.toString() == Number(val)) {
return new Number(val)
}
}
throw new CastError('number', value, this.path);
};
/*!
* ignore
*/
function handleSingle (val) {
return this.cast(val)
}
function handleArray (val) {
var self = this;
return val.map(function (m) {
return self.cast(m)
});
}
SchemaNumber.prototype.$conditionalHandlers = {
'$lt' : handleSingle
, '$lte': handleSingle
, '$gt' : handleSingle
, '$gte': handleSingle
, '$ne' : handleSingle
, '$in' : handleArray
, '$nin': handleArray
, '$mod': handleArray
, '$all': handleArray
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [value]
* @api private
*/
SchemaNumber.prototype.castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler)
throw new Error("Can't use " + $conditional + " with Number.");
return handler.call(this, val);
} else {
val = this.cast($conditional);
return val == null ? val : val
}
};
/*!
* Module exports.
*/
module.exports = SchemaNumber;

186
node_modules/mongoose/lib/schema/objectid.js generated vendored Normal file
View File

@ -0,0 +1,186 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, driver = global.MONGOOSE_DRIVER_PATH || './../drivers/node-mongodb-native'
, oid = require('../types/objectid')
, utils = require('../utils')
, Document
/**
* ObjectId SchemaType constructor.
*
* @param {String} key
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function ObjectId (key, options) {
SchemaType.call(this, key, options, 'ObjectID');
};
/*!
* Inherits from SchemaType.
*/
ObjectId.prototype.__proto__ = SchemaType.prototype;
/**
* Adds an auto-generated ObjectId default if turnOn is true.
* @param {Boolean} turnOn auto generated ObjectId defaults
* @api public
* @return {SchemaType} this
*/
ObjectId.prototype.auto = function (turnOn) {
if (turnOn) {
this.default(defaultId);
this.set(resetId)
}
return this;
};
/**
* Check required
*
* @api private
*/
ObjectId.prototype.checkRequired = function checkRequired (value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return null != value;
} else {
return value instanceof oid;
}
};
/**
* Casts to ObjectId
*
* @param {Object} value
* @param {Object} doc
* @param {Boolean} init whether this is an initialization cast
* @api private
*/
ObjectId.prototype.cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (null == value) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if (value instanceof oid) {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('ObjectId', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
if (value === null) return value;
if (value instanceof oid)
return value;
if (value._id && value._id instanceof oid)
return value._id;
if (value.toString) {
try {
return oid.fromString(value.toString());
} catch (err) {
throw new CastError('ObjectId', value, this.path);
}
}
throw new CastError('ObjectId', value, this.path);
};
/*!
* ignore
*/
function handleSingle (val) {
return this.cast(val);
}
function handleArray (val) {
var self = this;
return val.map(function (m) {
return self.cast(m);
});
}
ObjectId.prototype.$conditionalHandlers = {
'$ne': handleSingle
, '$in': handleArray
, '$nin': handleArray
, '$gt': handleSingle
, '$lt': handleSingle
, '$gte': handleSingle
, '$lte': handleSingle
, '$all': handleArray
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [val]
* @api private
*/
ObjectId.prototype.castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler)
throw new Error("Can't use " + $conditional + " with ObjectId.");
return handler.call(this, val);
} else {
return this.cast($conditional);
}
};
/*!
* ignore
*/
function defaultId () {
return new oid();
};
function resetId (v) {
this.$__._id = null;
return v;
}
/*!
* Module exports.
*/
module.exports = ObjectId;

312
node_modules/mongoose/lib/schema/string.js generated vendored Normal file
View File

@ -0,0 +1,312 @@
/*!
* Module dependencies.
*/
var SchemaType = require('../schematype')
, CastError = SchemaType.CastError
, utils = require('../utils')
, Document
/**
* String SchemaType constructor.
*
* @param {String} key
* @param {Object} options
* @inherits SchemaType
* @api private
*/
function SchemaString (key, options) {
this.enumValues = [];
this.regExp = null;
SchemaType.call(this, key, options, 'String');
};
/*!
* Inherits from SchemaType.
*/
SchemaString.prototype.__proto__ = SchemaType.prototype;
/**
* Adds enumeration values and a coinciding validator.
*
* ####Example:
*
* var states = 'opening open closing closed'.split(' ')
* var s = new Schema({ state: { type: String, enum: states })
* var M = db.model('M', s)
* var m = new M({ state: 'invalid' })
* m.save(function (err) {
* console.error(err) // validator error
* m.state = 'open'
* m.save() // success
* })
*
* @param {String} [args...] enumeration values
* @return {SchemaType} this
* @api public
*/
SchemaString.prototype.enum = function () {
var len = arguments.length;
if (!len || undefined === arguments[0] || false === arguments[0]) {
if (this.enumValidator){
this.enumValidator = false;
this.validators = this.validators.filter(function(v){
return v[1] != 'enum';
});
}
return this;
}
for (var i = 0; i < len; i++) {
if (undefined !== arguments[i]) {
this.enumValues.push(this.cast(arguments[i]));
}
}
if (!this.enumValidator) {
var values = this.enumValues;
this.enumValidator = function(v){
return undefined === v || ~values.indexOf(v);
};
this.validators.push([this.enumValidator, 'enum']);
}
return this;
};
/**
* Adds a lowercase setter.
*
* ####Example:
*
* var s = new Schema({ email: { type: String, lowercase: true }})
* var M = db.model('M', s);
* var m = new M({ email: 'SomeEmail@example.COM' });
* console.log(m.email) // someemail@example.com
*
* @api public
* @return {SchemaType} this
*/
SchemaString.prototype.lowercase = function () {
return this.set(function (v, self) {
if ('string' != typeof v) v = self.cast(v)
if (v) return v.toLowerCase();
return v;
});
};
/**
* Adds an uppercase setter.
*
* ####Example:
*
* var s = new Schema({ caps: { type: String, uppercase: true }})
* var M = db.model('M', s);
* var m = new M({ caps: 'an example' });
* console.log(m.caps) // AN EXAMPLE
*
* @api public
* @return {SchemaType} this
*/
SchemaString.prototype.uppercase = function () {
return this.set(function (v, self) {
if ('string' != typeof v) v = self.cast(v)
if (v) return v.toUpperCase();
return v;
});
};
/**
* Adds a trim setter.
*
* The string value will be trimmed when set.
*
* ####Example:
*
* var s = new Schema({ name: { type: String, trim: true }})
* var M = db.model('M', s)
* var string = ' some name '
* console.log(string.length) // 11
* var m = new M({ name: string })
* console.log(m.name.length) // 9
*
* @api public
* @return {SchemaType} this
*/
SchemaString.prototype.trim = function () {
return this.set(function (v, self) {
if ('string' != typeof v) v = self.cast(v)
if (v) return v.trim();
return v;
});
};
/**
* Sets a regexp validator.
*
* Any value that does not pass `regExp`.test(val) will fail validation.
*
* ####Example:
*
* var s = new Schema({ name: { type: String, match: /^a/ }})
* var M = db.model('M', s)
* var m = new M({ name: 'invalid' })
* m.validate(function (err) {
* console.error(err) // validation error
* m.name = 'apples'
* m.validate(function (err) {
* assert.ok(err) // success
* })
* })
*
* @param {RegExp} regExp regular expression to test against
* @return {SchemaType} this
* @api public
*/
SchemaString.prototype.match = function match (regExp) {
this.validators.push([function(v){
return null != v && '' !== v
? regExp.test(v)
: true
}, 'regexp']);
return this;
};
/**
* Check required
*
* @param {String|null|undefined} value
* @api private
*/
SchemaString.prototype.checkRequired = function checkRequired (value, doc) {
if (SchemaType._isRef(this, value, doc, true)) {
return null != value;
} else {
return (value instanceof String || typeof value == 'string') && value.length;
}
};
/**
* Casts to String
*
* @api private
*/
SchemaString.prototype.cast = function (value, doc, init) {
if (SchemaType._isRef(this, value, doc, init)) {
// wait! we may need to cast this to a document
if (null == value) {
return value;
}
// lazy load
Document || (Document = require('./../document'));
if (value instanceof Document) {
value.$__.wasPopulated = true;
return value;
}
// setting a populated path
if ('string' == typeof value) {
return value;
} else if (Buffer.isBuffer(value) || !utils.isObject(value)) {
throw new CastError('string', value, this.path);
}
// Handle the case where user directly sets a populated
// path to a plain object; cast to the Model used in
// the population query.
var path = doc.$__fullPath(this.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
var pop = owner.populated(path, true);
var ret = new pop.options.model(value);
ret.$__.wasPopulated = true;
return ret;
}
if (value === null) {
return value;
}
if ('undefined' !== typeof value) {
// handle documents being passed
if (value._id && 'string' == typeof value._id) {
return value._id;
}
if (value.toString) {
return value.toString();
}
}
throw new CastError('string', value, this.path);
};
/*!
* ignore
*/
function handleSingle (val) {
return this.castForQuery(val);
}
function handleArray (val) {
var self = this;
return val.map(function (m) {
return self.castForQuery(m);
});
}
SchemaString.prototype.$conditionalHandlers = {
'$ne' : handleSingle
, '$in' : handleArray
, '$nin': handleArray
, '$gt' : handleSingle
, '$lt' : handleSingle
, '$gte': handleSingle
, '$lte': handleSingle
, '$all': handleArray
, '$regex': handleSingle
, '$options': handleSingle
};
/**
* Casts contents for queries.
*
* @param {String} $conditional
* @param {any} [val]
* @api private
*/
SchemaString.prototype.castForQuery = function ($conditional, val) {
var handler;
if (arguments.length === 2) {
handler = this.$conditionalHandlers[$conditional];
if (!handler)
throw new Error("Can't use " + $conditional + " with String.");
return handler.call(this, val);
} else {
val = $conditional;
if (val instanceof RegExp) return val;
return this.cast(val);
}
};
/*!
* Module exports.
*/
module.exports = SchemaString;

34
node_modules/mongoose/lib/schemadefault.js generated vendored Normal file
View File

@ -0,0 +1,34 @@
/*!
* Module dependencies.
*/
var Schema = require('./schema')
/**
* Default model for querying the system.profiles collection.
*
* @property system.profile
* @receiver exports
* @api private
*/
exports['system.profile'] = new Schema({
ts: Date
, info: String // deprecated
, millis: Number
, op: String
, ns: String
, query: Schema.Types.Mixed
, updateobj: Schema.Types.Mixed
, ntoreturn: Number
, nreturned: Number
, nscanned: Number
, responseLength: Number
, client: String
, user: String
, idhack: Boolean
, scanAndOrder: Boolean
, keyUpdates: Number
, cursorid: Number
}, { noVirtualId: true, noId: true });

628
node_modules/mongoose/lib/schematype.js generated vendored Normal file
View File

@ -0,0 +1,628 @@
/*!
* Module dependencies.
*/
var utils = require('./utils');
var CastError = require('./error').CastError;
var ValidatorError = require('./error').ValidatorError;
/**
* SchemaType constructor
*
* @param {String} path
* @param {Object} [options]
* @param {String} [instance]
* @api public
*/
function SchemaType (path, options, instance) {
this.path = path;
this.instance = instance;
this.validators = [];
this.setters = [];
this.getters = [];
this.options = options;
this._index = null;
this.selected;
for (var i in options) if (this[i] && 'function' == typeof this[i]) {
// { unique: true, index: true }
if ('index' == i && this._index) continue;
var opts = Array.isArray(options[i])
? options[i]
: [options[i]];
this[i].apply(this, opts);
}
};
/**
* Sets a default value for this SchemaType.
*
* ####Example:
*
* var schema = new Schema({ n: { type: Number, default: 10 })
* var M = db.model('M', schema)
* var m = new M;
* console.log(m.n) // 10
*
* Defaults can be either `functions` which return the value to use as the default or the literal value itself. Either way, the value will be cast based on its schema type before being set during document creation.
*
* ####Example:
*
* // values are cast:
* var schema = new Schema({ aNumber: Number, default: "4.815162342" })
* var M = db.model('M', schema)
* var m = new M;
* console.log(m.aNumber, typeof m.aNumber) // 4.815162342 "number"
*
* @param {Function|any} val the default value
* @return {defaultValue}
* @api public
*/
SchemaType.prototype.default = function (val) {
if (1 === arguments.length) {
this.defaultValue = typeof val === 'function'
? val
: this.cast(val);
return this;
} else if (arguments.length > 1) {
this.defaultValue = utils.args(arguments);
}
return this.defaultValue;
};
/**
* Declares the index options for this schematype.
*
* ####Example:
*
* var s = new Schema({ name: { type: String, index: true })
* var s = new Schema({ loc: { type: [Number], index: 'hashed' })
* var s = new Schema({ loc: { type: [Number], index: '2d', sparse: true })
* var s = new Schema({ loc: { type: [Number], index: { type: '2dsphere', sparse: true }})
* var s = new Schema({ date: { type: Date, index: { unique: true, expires: '1d' }})
* Schema.path('my.path').index(true);
* Schema.path('my.date').index({ expires: 60 });
* Schema.path('my.path').index({ unique: true, sparse: true });
*
* ####NOTE:
*
* _Indexes are created in the background by default. Specify `background: false` to override._
*
* [Direction doesn't matter for single key indexes](http://www.mongodb.org/display/DOCS/Indexes#Indexes-CompoundKeysIndexes)
*
* @param {Object|Boolean|String} options
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.index = function (options) {
this._index = options;
utils.expires(this._index);
return this;
};
/**
* Declares an unique index.
*
* ####Example:
*
* var s = new Schema({ name: { type: String, unique: true })
* Schema.path('name').index({ unique: true });
*
* _NOTE: violating the constraint returns an `E11000` error from MongoDB when saving, not a Mongoose validation error._
*
* @param {Boolean} bool
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.unique = function (bool) {
if (null == this._index || 'boolean' == typeof this._index) {
this._index = {};
} else if ('string' == typeof this._index) {
this._index = { type: this._index };
}
this._index.unique = bool;
return this;
};
/**
* Declares a sparse index.
*
* ####Example:
*
* var s = new Schema({ name: { type: String, sparse: true })
* Schema.path('name').index({ sparse: true });
*
* @param {Boolean} bool
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.sparse = function (bool) {
if (null == this._index || 'boolean' == typeof this._index) {
this._index = {};
} else if ('string' == typeof this._index) {
this._index = { type: this._index };
}
this._index.sparse = bool;
return this;
};
/**
* Adds a setter to this schematype.
*
* ####Example:
*
* function capitalize (val) {
* if ('string' != typeof val) val = '';
* return val.charAt(0).toUpperCase() + val.substring(1);
* }
*
* // defining within the schema
* var s = new Schema({ name: { type: String, set: capitalize }})
*
* // or by retreiving its SchemaType
* var s = new Schema({ name: String })
* s.path('name').set(capitalize)
*
* Setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key.
*
* Suppose you are implementing user registration for a website. Users provide an email and password, which gets saved to mongodb. The email is a string that you will want to normalize to lower case, in order to avoid one email having more than one account -- e.g., otherwise, avenue@q.com can be registered for 2 accounts via avenue@q.com and AvEnUe@Q.CoM.
*
* You can set up email lower case normalization easily via a Mongoose setter.
*
* function toLower (v) {
* return v.toLowerCase();
* }
*
* var UserSchema = new Schema({
* email: { type: String, set: toLower }
* })
*
* var User = db.model('User', UserSchema)
*
* var user = new User({email: 'AVENUE@Q.COM'})
* console.log(user.email); // 'avenue@q.com'
*
* // or
* var user = new User
* user.email = 'Avenue@Q.com'
* console.log(user.email) // 'avenue@q.com'
*
* As you can see above, setters allow you to transform the data before it gets to the raw mongodb document and is set as a value on an actual key.
*
* _NOTE: we could have also just used the built-in `lowercase: true` SchemaType option instead of defining our own function._
*
* new Schema({ email: { type: String, lowercase: true }})
*
* Setters are also passed a second argument, the schematype on which the setter was defined. This allows for tailored behavior based on options passed in the schema.
*
* function inspector (val, schematype) {
* if (schematype.options.required) {
* return schematype.path + ' is required';
* } else {
* return val;
* }
* }
*
* var VirusSchema = new Schema({
* name: { type: String, required: true, set: inspector },
* taxonomy: { type: String, set: inspector }
* })
*
* var Virus = db.model('Virus', VirusSchema);
* var v = new Virus({ name: 'Parvoviridae', taxonomy: 'Parvovirinae' });
*
* console.log(v.name); // name is required
* console.log(v.taxonomy); // Parvovirinae
*
* @param {Function} fn
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.set = function (fn) {
if ('function' != typeof fn)
throw new TypeError('A setter must be a function.');
this.setters.push(fn);
return this;
};
/**
* Adds a getter to this schematype.
*
* ####Example:
*
* function dob (val) {
* if (!val) return val;
* return (val.getMonth() + 1) + "/" + val.getDate() + "/" + val.getFullYear();
* }
*
* // defining within the schema
* var s = new Schema({ born: { type: Date, get: dob })
*
* // or by retreiving its SchemaType
* var s = new Schema({ born: Date })
* s.path('born').get(dob)
*
* Getters allow you to transform the representation of the data as it travels from the raw mongodb document to the value that you see.
*
* Suppose you are storing credit card numbers and you want to hide everything except the last 4 digits to the mongoose user. You can do so by defining a getter in the following way:
*
* function obfuscate (cc) {
* return '****-****-****-' + cc.slice(cc.length-4, cc.length);
* }
*
* var AccountSchema = new Schema({
* creditCardNumber: { type: String, get: obfuscate }
* });
*
* var Account = db.model('Account', AccountSchema);
*
* Account.findById(id, function (err, found) {
* console.log(found.creditCardNumber); // '****-****-****-1234'
* });
*
* Getters are also passed a second argument, the schematype on which the getter was defined. This allows for tailored behavior based on options passed in the schema.
*
* function inspector (val, schematype) {
* if (schematype.options.required) {
* return schematype.path + ' is required';
* } else {
* return schematype.path + ' is not';
* }
* }
*
* var VirusSchema = new Schema({
* name: { type: String, required: true, get: inspector },
* taxonomy: { type: String, get: inspector }
* })
*
* var Virus = db.model('Virus', VirusSchema);
*
* Virus.findById(id, function (err, virus) {
* console.log(virus.name); // name is required
* console.log(virus.taxonomy); // taxonomy is not
* })
*
* @param {Function} fn
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.get = function (fn) {
if ('function' != typeof fn)
throw new TypeError('A getter must be a function.');
this.getters.push(fn);
return this;
};
/**
* Adds validator(s) for this document path.
*
* Validators always receive the value to validate as their first argument and must return `Boolean`. Returning false is interpreted as validation failure.
*
* ####Examples:
*
* function validator (val) {
* return val == 'something';
* }
*
* new Schema({ name: { type: String, validate: validator }});
*
* // with a custom error message
*
* var custom = [validator, 'validation failed']
* new Schema({ name: { type: String, validate: custom }});
*
* var many = [
* { validator: validator, msg: 'uh oh' }
* , { validator: fn, msg: 'failed' }
* ]
* new Schema({ name: { type: String, validate: many }});
*
* // or utilizing SchemaType methods directly:
*
* var schema = new Schema({ name: 'string' });
* schema.path('name').validate(validator, 'validation failed');
*
* ####Asynchronous validation:
*
* Passing a validator function that receives two arguments tells mongoose that the validator is an asynchronous validator. The second argument is an callback function that must be passed either `true` or `false` when validation is complete.
*
* schema.path('name').validate(function (value, respond) {
* doStuff(value, function () {
* ...
* respond(false); // validation failed
* })
* }, 'my error type');
*
* You might use asynchronous validators to retreive other documents from the database to validate against or to meet other I/O bound validation needs.
*
* Validation occurs `pre('save')` or whenever you manually execute [document#validate](#document_Document-validate).
*
* If validation fails during `pre('save')` and no callback was passed to receive the error, an `error` event will be emitted on your Models associated db [connection](#connection_Connection), passing the validation error object along.
*
* var conn = mongoose.createConnection(..);
* conn.on('error', handleError);
*
* var Product = conn.model('Product', yourSchema);
* var dvd = new Product(..);
* dvd.save(); // emits error on the `conn` above
*
* If you desire handling these errors at the Model level, attach an `error` listener to your Model and the event will instead be emitted there.
*
* // registering an error listener on the Model lets us handle errors more locally
* Product.on('error', handleError);
*
* @param {RegExp|Function|Object} obj validator
* @param {String} [error] optional error message
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.validate = function (obj, error) {
if ('function' == typeof obj || obj && 'RegExp' === obj.constructor.name) {
this.validators.push([obj, error]);
return this;
}
var i = arguments.length
, arg
while (i--) {
arg = arguments[i];
if (!(arg && 'Object' == arg.constructor.name)) {
var msg = 'Invalid validator. Received (' + typeof arg + ') '
+ arg
+ '. See http://mongoosejs.com/docs/api.html#schematype_SchemaType-validate';
throw new Error(msg);
}
this.validate(arg.validator, arg.msg);
}
return this;
};
/**
* Adds a required validator to this schematype.
*
* ####Example:
*
* var s = new Schema({ born: { type: Date, required: true })
* // or
* Schema.path('name').required(true);
*
*
* @param {Boolean} required enable/disable the validator
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.required = function (required) {
var self = this;
function __checkRequired (v) {
// in here, `this` refers to the validating document.
// no validation when this path wasn't selected in the query.
if ('isSelected' in this &&
!this.isSelected(self.path) &&
!this.isModified(self.path)) return true;
return self.checkRequired(v, this);
}
if (false === required) {
this.isRequired = false;
this.validators = this.validators.filter(function (v) {
return v[0].name !== '__checkRequired';
});
} else {
this.isRequired = true;
this.validators.push([__checkRequired, 'required']);
}
return this;
};
/**
* Gets the default value
*
* @param {Object} scope the scope which callback are executed
* @param {Boolean} init
* @api private
*/
SchemaType.prototype.getDefault = function (scope, init) {
var ret = 'function' === typeof this.defaultValue
? this.defaultValue.call(scope)
: this.defaultValue;
if (null !== ret && undefined !== ret) {
return this.cast(ret, scope, init);
} else {
return ret;
}
};
/**
* Applies setters
*
* @param {Object} value
* @param {Object} scope
* @param {Boolean} init
* @api private
*/
SchemaType.prototype.applySetters = function (value, scope, init, priorVal) {
if (SchemaType._isRef(this, value, scope, init)) {
return init
? value
: this.cast(value, scope, init, priorVal);
}
var v = value
, setters = this.setters
, len = setters.length
if (!len) {
if (null === v || undefined === v) return v;
return this.cast(v, scope, init, priorVal)
}
while (len--) {
v = setters[len].call(scope, v, this);
}
if (null === v || undefined === v) return v;
// do not cast until all setters are applied #665
v = this.cast(v, scope, init, priorVal);
return v;
};
/**
* Applies getters to a value
*
* @param {Object} value
* @param {Object} scope
* @api private
*/
SchemaType.prototype.applyGetters = function (value, scope) {
if (SchemaType._isRef(this, value, scope, true)) return value;
var v = value
, getters = this.getters
, len = getters.length;
if (!len) {
return v;
}
while (len--) {
v = getters[len].call(scope, v, this);
}
return v;
};
/**
* Sets default `select()` behavior for this path.
*
* Set to `true` if this path should always be included in the results, `false` if it should be excluded by default. This setting can be overridden at the query level.
*
* ####Example:
*
* T = db.model('T', new Schema({ x: { type: String, select: true }}));
* T.find(..); // field x will always be selected ..
* // .. unless overridden;
* T.find().select('-x').exec(callback);
*
* @param {Boolean} val
* @return {SchemaType} this
* @api public
*/
SchemaType.prototype.select = function select (val) {
this.selected = !! val;
return this;
}
/**
* Performs a validation of `value` using the validators declared for this SchemaType.
*
* @param {any} value
* @param {Function} callback
* @param {Object} scope
* @api private
*/
SchemaType.prototype.doValidate = function (value, fn, scope) {
var err = false
, path = this.path
, count = this.validators.length;
if (!count) return fn(null);
function validate (ok, msg, val) {
if (err) return;
if (ok === undefined || ok) {
--count || fn(null);
} else {
fn(err = new ValidatorError(path, msg, val));
}
}
this.validators.forEach(function (v) {
var validator = v[0]
, message = v[1];
if (validator instanceof RegExp) {
validate(validator.test(value), message, value);
} else if ('function' === typeof validator) {
if (2 === validator.length) {
validator.call(scope, value, function (ok) {
validate(ok, message, value);
});
} else {
validate(validator.call(scope, value), message, value);
}
}
});
};
/**
* Determines if value is a valid Reference.
*
* @param {SchemaType} self
* @param {Object} value
* @param {Document} doc
* @param {Boolean} init
* @return {Boolean}
* @api private
*/
SchemaType._isRef = function (self, value, doc, init) {
// fast path
var ref = init && self.options && self.options.ref;
if (!ref && doc && doc.$__fullPath) {
// checks for
// - this populated with adhoc model and no ref was set in schema OR
// - setting / pushing values after population
var path = doc.$__fullPath(self.path);
var owner = doc.ownerDocument ? doc.ownerDocument() : doc;
ref = owner.populated(path);
}
if (ref) {
if (null == value) return true;
if (!Buffer.isBuffer(value) && // buffers are objects too
'Binary' != value._bsontype // raw binary value from the db
&& utils.isObject(value) // might have deselected _id in population query
) {
return true;
}
}
return false;
}
/*!
* Module exports.
*/
module.exports = exports = SchemaType;
exports.CastError = CastError;
exports.ValidatorError = ValidatorError;

179
node_modules/mongoose/lib/statemachine.js generated vendored Normal file
View File

@ -0,0 +1,179 @@
/*!
* Module dependencies.
*/
var utils = require('./utils');
/*!
* StateMachine represents a minimal `interface` for the
* constructors it builds via StateMachine.ctor(...).
*
* @api private
*/
var StateMachine = module.exports = exports = function StateMachine () {
this.paths = {};
this.states = {};
}
/*!
* StateMachine.ctor('state1', 'state2', ...)
* A factory method for subclassing StateMachine.
* The arguments are a list of states. For each state,
* the constructor's prototype gets state transition
* methods named after each state. These transition methods
* place their path argument into the given state.
*
* @param {String} state
* @param {String} [state]
* @return {Function} subclass constructor
* @private
*/
StateMachine.ctor = function () {
var states = utils.args(arguments);
var ctor = function () {
StateMachine.apply(this, arguments);
this.stateNames = states;
var i = states.length
, state;
while (i--) {
state = states[i];
this.states[state] = {};
}
};
ctor.prototype.__proto__ = StateMachine.prototype;
states.forEach(function (state) {
// Changes the `path`'s state to `state`.
ctor.prototype[state] = function (path) {
this._changeState(path, state);
}
});
return ctor;
};
/*!
* This function is wrapped by the state change functions:
*
* - `require(path)`
* - `modify(path)`
* - `init(path)`
*
* @api private
*/
StateMachine.prototype._changeState = function _changeState (path, nextState) {
var prevBucket = this.states[this.paths[path]];
if (prevBucket) delete prevBucket[path];
this.paths[path] = nextState;
this.states[nextState][path] = true;
}
/*!
* ignore
*/
StateMachine.prototype.clear = function clear (state) {
var keys = Object.keys(this.states[state])
, i = keys.length
, path
while (i--) {
path = keys[i];
delete this.states[state][path];
delete this.paths[path];
}
}
/*!
* Checks to see if at least one path is in the states passed in via `arguments`
* e.g., this.some('required', 'inited')
*
* @param {String} state that we want to check for.
* @private
*/
StateMachine.prototype.some = function some () {
var self = this;
var what = arguments.length ? arguments : this.stateNames;
return Array.prototype.some.call(what, function (state) {
return Object.keys(self.states[state]).length;
});
}
/*!
* This function builds the functions that get assigned to `forEach` and `map`,
* since both of those methods share a lot of the same logic.
*
* @param {String} iterMethod is either 'forEach' or 'map'
* @return {Function}
* @api private
*/
StateMachine.prototype._iter = function _iter (iterMethod) {
return function () {
var numArgs = arguments.length
, states = utils.args(arguments, 0, numArgs-1)
, callback = arguments[numArgs-1];
if (!states.length) states = this.stateNames;
var self = this;
var paths = states.reduce(function (paths, state) {
return paths.concat(Object.keys(self.states[state]));
}, []);
return paths[iterMethod](function (path, i, paths) {
return callback(path, i, paths);
});
};
}
/*!
* Iterates over the paths that belong to one of the parameter states.
*
* The function profile can look like:
* this.forEach(state1, fn); // iterates over all paths in state1
* this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
* this.forEach(fn); // iterates over all paths in all states
*
* @param {String} [state]
* @param {String} [state]
* @param {Function} callback
* @private
*/
StateMachine.prototype.forEach = function forEach () {
this.forEach = this._iter('forEach');
return this.forEach.apply(this, arguments);
}
/*!
* Maps over the paths that belong to one of the parameter states.
*
* The function profile can look like:
* this.forEach(state1, fn); // iterates over all paths in state1
* this.forEach(state1, state2, fn); // iterates over all paths in state1 or state2
* this.forEach(fn); // iterates over all paths in all states
*
* @param {String} [state]
* @param {String} [state]
* @param {Function} callback
* @return {Array}
* @private
*/
StateMachine.prototype.map = function map () {
this.map = this._iter('map');
return this.map.apply(this, arguments);
}

679
node_modules/mongoose/lib/types/array.js generated vendored Normal file
View File

@ -0,0 +1,679 @@
/*!
* Module dependencies.
*/
var EmbeddedDocument = require('./embedded');
var Document = require('../document');
var ObjectId = require('./objectid');
var utils = require('../utils');
var isMongooseObject = utils.isMongooseObject;
/**
* Mongoose Array constructor.
*
* ####NOTE:
*
* _Values always have to be passed to the constructor to initialize, otherwise `MongooseArray#push` will mark the array as modified._
*
* @param {Array} values
* @param {String} path
* @param {Document} doc parent document
* @api private
* @inherits Array
* @see http://bit.ly/f6CnZU
*/
function MongooseArray (values, path, doc) {
var arr = [];
arr.push.apply(arr, values);
arr.__proto__ = MongooseArray.prototype;
arr._atomics = {};
arr.validators = [];
arr._path = path;
if (doc) {
arr._parent = doc;
arr._schema = doc.schema.path(path);
}
return arr;
};
/*!
* Inherit from Array
*/
MongooseArray.prototype = new Array;
/**
* Stores a queue of atomic operations to perform
*
* @property _atomics
* @api private
*/
MongooseArray.prototype._atomics;
/**
* Parent owner document
*
* @property _parent
* @api private
*/
MongooseArray.prototype._parent;
/**
* Casts a member based on this arrays schema.
*
* @param {any} value
* @return value the casted value
* @api private
*/
MongooseArray.prototype._cast = function (value) {
var owner = this._owner;
var populated = false;
var Model;
if (this._parent) {
// if a populated array, we must cast to the same model
// instance as specified in the original query.
if (!owner) {
owner = this._owner = this._parent.ownerDocument
? this._parent.ownerDocument()
: this._parent;
}
populated = owner.populated(this._path, true);
}
if (populated && null != value) {
// cast to the populated Models schema
var Model = populated.options.model;
// only objects are permitted so we can safely assume that
// non-objects are to be interpreted as _id
if (Buffer.isBuffer(value) ||
value instanceof ObjectId || !utils.isObject(value)) {
value = { _id: value };
}
value = new Model(value);
return this._schema.caster.cast(value, this._parent, true)
}
return this._schema.caster.cast(value, this._parent, false)
}
/**
* Marks this array as modified.
*
* If it bubbles up from an embedded document change, then it takes the following arguments (otherwise, takes 0 arguments)
*
* @param {EmbeddedDocument} embeddedDoc the embedded doc that invoked this method on the Array
* @param {String} embeddedPath the path which changed in the embeddedDoc
* @api private
*/
MongooseArray.prototype._markModified = function (elem, embeddedPath) {
var parent = this._parent
, dirtyPath;
if (parent) {
dirtyPath = this._path;
if (arguments.length) {
if (null != embeddedPath) {
// an embedded doc bubbled up the change
dirtyPath = dirtyPath + '.' + this.indexOf(elem) + '.' + embeddedPath;
} else {
// directly set an index
dirtyPath = dirtyPath + '.' + elem;
}
}
parent.markModified(dirtyPath);
}
return this;
};
/**
* Register an atomic operation with the parent.
*
* @param {Array} op operation
* @param {any} val
* @api private
*/
MongooseArray.prototype._registerAtomic = function (op, val) {
if ('$set' == op) {
// $set takes precedence over all other ops.
// mark entire array modified.
this._atomics = { $set: val };
return this;
}
var atomics = this._atomics;
// reset pop/shift after save
if ('$pop' == op && !('$pop' in atomics)) {
var self = this;
this._parent.once('save', function () {
self._popped = self._shifted = null;
});
}
// check for impossible $atomic combos (Mongo denies more than one
// $atomic op on a single path
if (this._atomics.$set ||
Object.keys(atomics).length && !(op in atomics)) {
// a different op was previously registered.
// save the entire thing.
this._atomics = { $set: this };
return this;
}
if (op === '$pullAll' || op === '$pushAll' || op === '$addToSet') {
atomics[op] || (atomics[op] = []);
atomics[op] = atomics[op].concat(val);
} else if (op === '$pullDocs') {
var pullOp = atomics['$pull'] || (atomics['$pull'] = {})
, selector = pullOp['_id'] || (pullOp['_id'] = {'$in' : [] });
selector['$in'] = selector['$in'].concat(val);
} else {
atomics[op] = val;
}
return this;
};
/**
* Depopulates stored atomic operation values as necessary for direct insertion to MongoDB.
*
* If no atomics exist, we return all array values after conversion.
*
* @return {Array}
* @method $__getAtomics
* @memberOf MongooseArray
* @api private
*/
MongooseArray.prototype.$__getAtomics = function () {
var ret = [];
var keys = Object.keys(this._atomics);
var i = keys.length;
if (0 === i) {
ret[0] = ['$set', this.toObject({ depopulate: 1 })];
return ret;
}
while (i--) {
var op = keys[i];
var val = this._atomics[op];
// the atomic values which are arrays are not MongooseArrays. we
// need to convert their elements as if they were MongooseArrays
// to handle populated arrays versus DocumentArrays properly.
if (isMongooseObject(val)) {
val = val.toObject({ depopulate: 1 });
} else if (Array.isArray(val)) {
val = this.toObject.call(val, { depopulate: 1 });
} else if (val.valueOf) {
val = val.valueOf();
}
if ('$addToSet' == op) {
val = { $each: val }
}
ret.push([op, val]);
}
return ret;
}
/**
* Returns the number of pending atomic operations to send to the db for this array.
*
* @api private
* @return {Number}
*/
MongooseArray.prototype.hasAtomics = function hasAtomics () {
if (!(this._atomics && 'Object' === this._atomics.constructor.name)) {
return 0;
}
return Object.keys(this._atomics).length;
}
/**
* Wraps [`Array#push`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/push) with proper change tracking.
*
* @param {Object} [args...]
* @api public
*/
MongooseArray.prototype.push = function () {
var values = [].map.call(arguments, this._cast, this)
, ret = [].push.apply(this, values);
// $pushAll might be fibbed (could be $push). But it makes it easier to
// handle what could have been $push, $pushAll combos
this._registerAtomic('$pushAll', values);
this._markModified();
return ret;
};
/**
* Pushes items to the array non-atomically.
*
* ####NOTE:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @param {any} [args...]
* @api public
*/
MongooseArray.prototype.nonAtomicPush = function () {
var values = [].map.call(arguments, this._cast, this)
, ret = [].push.apply(this, values);
this._registerAtomic('$set', this);
this._markModified();
return ret;
};
/**
* Pops the array atomically at most one time per document `save()`.
*
* #### NOTE:
*
* _Calling this mulitple times on an array before saving sends the same command as calling it once._
* _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._
*
* doc.array = [1,2,3];
*
* var popped = doc.array.$pop();
* console.log(popped); // 3
* console.log(doc.array); // [1,2]
*
* // no affect
* popped = doc.array.$pop();
* console.log(doc.array); // [1,2]
*
* doc.save(function (err) {
* if (err) return handleError(err);
*
* // we saved, now $pop works again
* popped = doc.array.$pop();
* console.log(popped); // 2
* console.log(doc.array); // [1]
* })
*
* @api public
* @method $pop
* @memberOf MongooseArray
* @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop
*/
MongooseArray.prototype.$pop = function () {
this._registerAtomic('$pop', 1);
this._markModified();
// only allow popping once
if (this._popped) return;
this._popped = true;
return [].pop.call(this);
};
/**
* Wraps [`Array#pop`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/pop) with proper change tracking.
*
* ####Note:
*
* _marks the entire array as modified which will pass the entire thing to $set potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @see MongooseArray#$pop #types_array_MongooseArray-%24pop
* @api public
*/
MongooseArray.prototype.pop = function () {
var ret = [].pop.call(this);
this._registerAtomic('$set', this);
this._markModified();
return ret;
};
/**
* Atomically shifts the array at most one time per document `save()`.
*
* ####NOTE:
*
* _Calling this mulitple times on an array before saving sends the same command as calling it once._
* _This update is implemented using the MongoDB [$pop](http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop) method which enforces this restriction._
*
* doc.array = [1,2,3];
*
* var shifted = doc.array.$shift();
* console.log(shifted); // 1
* console.log(doc.array); // [2,3]
*
* // no affect
* shifted = doc.array.$shift();
* console.log(doc.array); // [2,3]
*
* doc.save(function (err) {
* if (err) return handleError(err);
*
* // we saved, now $shift works again
* shifted = doc.array.$shift();
* console.log(shifted ); // 2
* console.log(doc.array); // [3]
* })
*
* @api public
* @memberOf MongooseArray
* @method $shift
* @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pop
*/
MongooseArray.prototype.$shift = function $shift () {
this._registerAtomic('$pop', -1);
this._markModified();
// only allow shifting once
if (this._shifted) return;
this._shifted = true;
return [].shift.call(this);
};
/**
* Wraps [`Array#shift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
*
* ####Example:
*
* doc.array = [2,3];
* var res = doc.array.shift();
* console.log(res) // 2
* console.log(doc.array) // [3]
*
* ####Note:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @api public
*/
MongooseArray.prototype.shift = function () {
var ret = [].shift.call(this);
this._registerAtomic('$set', this);
this._markModified();
return ret;
};
/**
* Pulls items from the array atomically.
*
* ####Examples:
*
* doc.array.pull(ObjectId)
* doc.array.pull({ _id: 'someId' })
* doc.array.pull(36)
* doc.array.pull('tag 1', 'tag 2')
*
* To remove a document from a subdocument array we may pass an object with a matching `_id`.
*
* doc.subdocs.push({ _id: 4815162342 })
* doc.subdocs.pull({ _id: 4815162342 }) // removed
*
* Or we may passing the _id directly and let mongoose take care of it.
*
* doc.subdocs.push({ _id: 4815162342 })
* doc.subdocs.pull(4815162342); // works
*
* @param {any} [args...]
* @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull
* @api public
*/
MongooseArray.prototype.pull = function () {
var values = [].map.call(arguments, this._cast, this)
, cur = this._parent.get(this._path)
, i = cur.length
, mem;
while (i--) {
mem = cur[i];
if (mem instanceof EmbeddedDocument) {
if (values.some(function (v) { return v.equals(mem); } )) {
[].splice.call(cur, i, 1);
}
} else if (~cur.indexOf.call(values, mem)) {
[].splice.call(cur, i, 1);
}
}
if (values[0] instanceof EmbeddedDocument) {
this._registerAtomic('$pullDocs', values.map( function (v) { return v._id; } ));
} else {
this._registerAtomic('$pullAll', values);
}
this._markModified();
return this;
};
/**
* Alias of [pull](#types_array_MongooseArray-pull)
*
* @see MongooseArray#pull #types_array_MongooseArray-pull
* @see mongodb http://www.mongodb.org/display/DOCS/Updating/#Updating-%24pull
* @api public
* @memberOf MongooseArray
* @method remove
*/
MongooseArray.prototype.remove = MongooseArray.prototype.pull;
/**
* Wraps [`Array#splice`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) with proper change tracking and casting.
*
* ####Note:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @api public
*/
MongooseArray.prototype.splice = function splice () {
var ret, vals, i;
if (arguments.length) {
vals = [];
for (i = 0; i < arguments.length; ++i) {
vals[i] = i < 2
? arguments[i]
: this._cast(arguments[i]);
}
ret = [].splice.apply(this, vals);
this._registerAtomic('$set', this);
this._markModified();
}
return ret;
}
/**
* Wraps [`Array#unshift`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/unshift) with proper change tracking.
*
* ####Note:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @api public
*/
MongooseArray.prototype.unshift = function () {
var values = [].map.call(arguments, this._cast, this);
[].unshift.apply(this, values);
this._registerAtomic('$set', this);
this._markModified();
return this.length;
};
/**
* Wraps [`Array#sort`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) with proper change tracking.
*
* ####NOTE:
*
* _marks the entire array as modified, which if saved, will store it as a `$set` operation, potentially overwritting any changes that happen between when you retrieved the object and when you save it._
*
* @api public
*/
MongooseArray.prototype.sort = function () {
var ret = [].sort.apply(this, arguments);
this._registerAtomic('$set', this);
this._markModified();
return ret;
}
/**
* Adds values to the array if not already present.
*
* ####Example:
*
* console.log(doc.array) // [2,3,4]
* var added = doc.array.addToSet(4,5);
* console.log(doc.array) // [2,3,4,5]
* console.log(added) // [5]
*
* @param {any} [args...]
* @return {Array} the values that were added
* @api public
*/
MongooseArray.prototype.addToSet = function addToSet () {
var values = [].map.call(arguments, this._cast, this)
, added = []
, type = values[0] instanceof EmbeddedDocument ? 'doc' :
values[0] instanceof Date ? 'date' :
'';
values.forEach(function (v) {
var found;
switch (type) {
case 'doc':
found = this.some(function(doc){ return doc.equals(v) });
break;
case 'date':
var val = +v;
found = this.some(function(d){ return +d === val });
break;
default:
found = ~this.indexOf(v);
}
if (!found) {
[].push.call(this, v);
this._registerAtomic('$addToSet', v);
this._markModified();
[].push.call(added, v);
}
}, this);
return added;
};
/**
* Sets the casted `val` at index `i` and marks the array modified.
*
* ####Example:
*
* // given documents based on the following
* var Doc = mongoose.model('Doc', new Schema({ array: [Number] }));
*
* var doc = new Doc({ array: [2,3,4] })
*
* console.log(doc.array) // [2,3,4]
*
* doc.array.set(1,"5");
* console.log(doc.array); // [2,5,4] // properly cast to number
* doc.save() // the change is saved
*
* // VS not using array#set
* doc.array[1] = "5";
* console.log(doc.array); // [2,"5",4] // no casting
* doc.save() // change is not saved
*
* @return {Array} this
* @api public
*/
MongooseArray.prototype.set = function set (i, val) {
this[i] = this._cast(val);
this._markModified(i);
return this;
}
/**
* Returns a native js Array.
*
* @param {Object} options
* @return {Array}
* @api public
*/
MongooseArray.prototype.toObject = function (options) {
if (options && options.depopulate) {
return this.map(function (doc) {
return doc instanceof Document
? doc.toObject(options)
: doc
});
}
return this.slice();
}
/**
* Helper for console.log
*
* @api public
*/
MongooseArray.prototype.inspect = function () {
return '[' + this.map(function (doc) {
return ' ' + doc;
}) + ' ]';
};
/**
* Return the index of `obj` or `-1` if not found.
*
* @param {Object} obj the item to look for
* @return {Number}
* @api public
*/
MongooseArray.prototype.indexOf = function indexOf (obj) {
if (obj instanceof ObjectId) obj = obj.toString();
for (var i = 0, len = this.length; i < len; ++i) {
if (obj == this[i])
return i;
}
return -1;
};
/*!
* Module exports.
*/
module.exports = exports = MongooseArray;

214
node_modules/mongoose/lib/types/buffer.js generated vendored Normal file
View File

@ -0,0 +1,214 @@
/*!
* Access driver.
*/
var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native';
/*!
* Module dependencies.
*/
var Binary = require(driver + '/binary');
/**
* Mongoose Buffer constructor.
*
* Values always have to be passed to the constructor to initialize.
*
* @param {Buffer} value
* @param {String} encode
* @param {Number} offset
* @api private
* @inherits Buffer
* @see http://bit.ly/f6CnZU
*/
function MongooseBuffer (value, encode, offset) {
var length = arguments.length;
var val;
if (0 === length || null === arguments[0] || undefined === arguments[0]) {
val = 0;
} else {
val = value;
}
var encoding;
var path;
var doc;
if (Array.isArray(encode)) {
// internal casting
path = encode[0];
doc = encode[1];
} else {
encoding = encode;
}
var buf = new Buffer(val, encoding, offset);
buf.__proto__ = MongooseBuffer.prototype;
// make sure these internal props don't show up in Object.keys()
Object.defineProperties(buf, {
validators: { value: [] }
, _path: { value: path }
, _parent: { value: doc }
});
if (doc && "string" === typeof path) {
Object.defineProperty(buf, '_schema', {
value: doc.schema.path(path)
});
}
buf._subtype = 0;
return buf;
};
/*!
* Inherit from Buffer.
*/
MongooseBuffer.prototype = new Buffer(0);
/**
* Parent owner document
*
* @api private
* @property _parent
*/
MongooseBuffer.prototype._parent;
/**
* Marks this buffer as modified.
*
* @api private
*/
MongooseBuffer.prototype._markModified = function () {
var parent = this._parent;
if (parent) {
parent.markModified(this._path);
}
return this;
};
/**
* Writes the buffer.
*/
MongooseBuffer.prototype.write = function () {
var written = Buffer.prototype.write.apply(this, arguments);
if (written > 0) {
this._markModified();
}
return written;
};
/**
* Copies the buffer.
*
* ####Note:
*
* `Buffer#copy` does not mark `target` as modified so you must copy from a `MongooseBuffer` for it to work as expected. This is a work around since `copy` modifies the target, not this.
*
* @return {MongooseBuffer}
* @param {Buffer} target
*/
MongooseBuffer.prototype.copy = function (target) {
var ret = Buffer.prototype.copy.apply(this, arguments);
if (target instanceof MongooseBuffer) {
target._markModified();
}
return ret;
};
/*!
* Compile other Buffer methods marking this buffer as modified.
*/
;(
// node < 0.5
'writeUInt8 writeUInt16 writeUInt32 writeInt8 writeInt16 writeInt32 ' +
'writeFloat writeDouble fill ' +
'utf8Write binaryWrite asciiWrite set ' +
// node >= 0.5
'writeUInt16LE writeUInt16BE writeUInt32LE writeUInt32BE ' +
'writeInt16LE writeInt16BE writeInt32LE writeInt32BE ' +
'writeFloatLE writeFloatBE writeDoubleLE writeDoubleBE'
).split(' ').forEach(function (method) {
if (!Buffer.prototype[method]) return;
MongooseBuffer.prototype[method] = new Function(
'var ret = Buffer.prototype.'+method+'.apply(this, arguments);' +
'this._markModified();' +
'return ret;'
)
});
/**
* Converts this buffer to its Binary type representation.
*
* ####SubTypes:
*
* var bson = require('bson')
* bson.BSON_BINARY_SUBTYPE_DEFAULT
* bson.BSON_BINARY_SUBTYPE_FUNCTION
* bson.BSON_BINARY_SUBTYPE_BYTE_ARRAY
* bson.BSON_BINARY_SUBTYPE_UUID
* bson.BSON_BINARY_SUBTYPE_MD5
* bson.BSON_BINARY_SUBTYPE_USER_DEFINED
*
* doc.buffer.toObject(bson.BSON_BINARY_SUBTYPE_USER_DEFINED);
*
* @see http://bsonspec.org/#/specification
* @param {Hex} [subtype]
* @return {Binary}
* @api public
*/
MongooseBuffer.prototype.toObject = function (options) {
var subtype = 'number' == typeof options
? options
: (this._subtype || 0x00);
return new Binary(this, subtype);
};
/**
* Determines if this buffer is equals to `other` buffer
*
* @param {Buffer} other
* @return {Boolean}
*/
MongooseBuffer.prototype.equals = function (other) {
if (!Buffer.isBuffer(other)) {
return false;
}
if (this.length !== other.length) {
return false;
}
for (var i = 0; i < this.length; ++i) {
if (this[i] !== other[i]) return false;
}
return true;
}
/*!
* Module exports.
*/
MongooseBuffer.Binary = Binary;
module.exports = MongooseBuffer;

192
node_modules/mongoose/lib/types/documentarray.js generated vendored Normal file
View File

@ -0,0 +1,192 @@
/*!
* Module dependencies.
*/
var MongooseArray = require('./array')
, driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native'
, ObjectId = require(driver + '/objectid')
, ObjectIdSchema = require('../schema/objectid')
, utils = require('../utils')
, util = require('util')
, Document = require('../document')
/**
* DocumentArray constructor
*
* @param {Array} values
* @param {String} path the path to this array
* @param {Document} doc parent document
* @api private
* @return {MongooseDocumentArray}
* @inherits MongooseArray
* @see http://bit.ly/f6CnZU
*/
function MongooseDocumentArray (values, path, doc) {
var arr = [];
// Values always have to be passed to the constructor to initialize, since
// otherwise MongooseArray#push will mark the array as modified to the parent.
arr.push.apply(arr, values);
arr.__proto__ = MongooseDocumentArray.prototype;
arr._atomics = {};
arr.validators = [];
arr._path = path;
if (doc) {
arr._parent = doc;
arr._schema = doc.schema.path(path);
doc.on('save', arr.notify('save'));
doc.on('isNew', arr.notify('isNew'));
}
return arr;
};
/*!
* Inherits from MongooseArray
*/
MongooseDocumentArray.prototype.__proto__ = MongooseArray.prototype;
/**
* Overrides MongooseArray#cast
*
* @api private
*/
MongooseDocumentArray.prototype._cast = function (value) {
if (value instanceof this._schema.casterConstructor) {
if (!(value.__parent && value.__parentArray)) {
// value may have been created using array.create()
value.__parent = this._parent;
value.__parentArray = this;
}
return value;
}
// handle cast('string') or cast(ObjectId) etc.
// only objects are permitted so we can safely assume that
// non-objects are to be interpreted as _id
if (Buffer.isBuffer(value) ||
value instanceof ObjectId || !utils.isObject(value)) {
value = { _id: value };
}
return new this._schema.casterConstructor(value, this);
};
/**
* Searches array items for the first document with a matching _id.
*
* ####Example:
*
* var embeddedDoc = m.array.id(some_id);
*
* @return {EmbeddedDocument|null} the subdocuent or null if not found.
* @param {ObjectId|String|Number|Buffer} id
* @api public
*/
MongooseDocumentArray.prototype.id = function (id) {
var casted
, sid
, _id
try {
casted = ObjectId.toString(ObjectIdSchema.prototype.cast.call({}, id));
} catch (e) {
casted = null;
}
for (var i = 0, l = this.length; i < l; i++) {
_id = this[i].get('_id');
if (_id instanceof Document) {
sid || (sid = String(id));
if (sid == _id._id) return this[i];
} else if (!(_id instanceof ObjectId)) {
sid || (sid = String(id));
if (sid == _id) return this[i];
} else if (casted == _id) {
return this[i];
}
}
return null;
};
/**
* Returns a native js Array of plain js objects
*
* ####NOTE:
*
* _Each sub-document is converted to a plain object by calling its `#toObject` method._
*
* @param {Object} [options] optional options to pass to each documents `toObject` method call during conversion
* @return {Array}
* @api public
*/
MongooseDocumentArray.prototype.toObject = function (options) {
return this.map(function (doc) {
return doc && doc.toObject(options) || null;
});
};
/**
* Helper for console.log
*
* @api public
*/
MongooseDocumentArray.prototype.inspect = function () {
return '[' + this.map(function (doc) {
if (doc) {
return doc.inspect
? doc.inspect()
: util.inspect(doc)
}
return 'null'
}).join('\n') + ']';
};
/**
* Creates a subdocument casted to this schema.
*
* This is the same subdocument constructor used for casting.
*
* @param {Object} obj the value to cast to this arrays SubDocument schema
* @api public
*/
MongooseDocumentArray.prototype.create = function (obj) {
return new this._schema.casterConstructor(obj);
}
/**
* Creates a fn that notifies all child docs of `event`.
*
* @param {String} event
* @return {Function}
* @api private
*/
MongooseDocumentArray.prototype.notify = function notify (event) {
var self = this;
return function notify (val) {
var i = self.length;
while (i--) {
if (!self[i]) continue;
self[i].emit(event, val);
}
}
}
/*!
* Module exports.
*/
module.exports = MongooseDocumentArray;

244
node_modules/mongoose/lib/types/embedded.js generated vendored Normal file
View File

@ -0,0 +1,244 @@
/*!
* Module dependencies.
*/
var Document = require('../document')
, inspect = require('util').inspect;
/**
* EmbeddedDocument constructor.
*
* @param {Object} obj js object returned from the db
* @param {MongooseDocumentArray} parentArr the parent array of this document
* @param {Boolean} skipId
* @inherits Document
* @api private
*/
function EmbeddedDocument (obj, parentArr, skipId, fields) {
if (parentArr) {
this.__parentArray = parentArr;
this.__parent = parentArr._parent;
} else {
this.__parentArray = undefined;
this.__parent = undefined;
}
Document.call(this, obj, fields, skipId);
var self = this;
this.on('isNew', function (val) {
self.isNew = val;
});
};
/*!
* Inherit from Document
*/
EmbeddedDocument.prototype.__proto__ = Document.prototype;
/**
* Marks the embedded doc modified.
*
* ####Example:
*
* var doc = blogpost.comments.id(hexstring);
* doc.mixed.type = 'changed';
* doc.markModified('mixed.type');
*
* @param {String} path the path which changed
* @api public
*/
EmbeddedDocument.prototype.markModified = function (path) {
if (!this.__parentArray) return;
this.$__.activePaths.modify(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);
};
/**
* Used as a stub for [hooks.js](https://github.com/bnoguchi/hooks-js/tree/31ec571cef0332e21121ee7157e0cf9728572cc3)
*
* ####NOTE:
*
* _This is a no-op. Does not actually save the doc to the db._
*
* @param {Function} [fn]
* @return {EmbeddedDocument} this
* @api private
*/
EmbeddedDocument.prototype.save = function(fn) {
if (fn)
fn(null);
return this;
};
/**
* Removes the subdocument from its parent array.
*
* @param {Function} [fn]
* @api public
*/
EmbeddedDocument.prototype.remove = function (fn) {
if (!this.__parentArray) return this;
var _id;
if (!this.willRemove) {
_id = this._doc._id;
if (!_id) {
throw new Error('For your own good, Mongoose does not know ' +
'how to remove an EmbeddedDocument that has no _id');
}
this.__parentArray.pull({ _id: _id });
this.willRemove = true;
}
if (fn)
fn(null);
return this;
};
/**
* Override #update method of parent documents.
* @api private
*/
EmbeddedDocument.prototype.update = function () {
throw new Error('The #update method is not available on EmbeddedDocuments');
}
/**
* Helper for console.log
*
* @api public
*/
EmbeddedDocument.prototype.inspect = function () {
return inspect(this.toObject());
};
/**
* Marks a path as invalid, causing validation to fail.
*
* @param {String} path the field to invalidate
* @param {String|Error} err error which states the reason `path` was invalid
* @return {Boolean}
* @api public
*/
EmbeddedDocument.prototype.invalidate = function (path, err, val, first) {
if (!this.__parent) {
var msg = 'Unable to invalidate a subdocument that has not been added to an array.'
throw new Error(msg);
}
var index = this.__parentArray.indexOf(this);
var parentPath = this.__parentArray._path;
var fullPath = [parentPath, index, path].join('.');
// sniffing arguments:
// need to check if user passed a value to keep
// our error message clean.
if (2 < arguments.length) {
this.__parent.invalidate(fullPath, err, val);
} else {
this.__parent.invalidate(fullPath, err);
}
if (first)
this.$__.validationError = this.ownerDocument().$__.validationError;
return true;
}
/**
* Returns the top level document of this sub-document.
*
* @return {Document}
*/
EmbeddedDocument.prototype.ownerDocument = function () {
if (this.$__.ownerDocument) {
return this.$__.ownerDocument;
}
var parent = this.__parent;
if (!parent) return this;
while (parent.__parent) {
parent = parent.__parent;
}
return this.$__.ownerDocument = parent;
}
/**
* Returns the full path to this document. If optional `path` is passed, it is appended to the full path.
*
* @param {String} [path]
* @return {String}
* @api private
* @method $__fullPath
* @memberOf EmbeddedDocument
*/
EmbeddedDocument.prototype.$__fullPath = function (path) {
if (!this.$__.fullPath) {
var parent = this;
if (!parent.__parent) return path;
var paths = [];
while (parent.__parent) {
paths.unshift(parent.__parentArray._path);
parent = parent.__parent;
}
this.$__.fullPath = paths.join('.');
if (!this.$__.ownerDocument) {
// optimization
this.$__.ownerDocument = parent;
}
}
return path
? this.$__.fullPath + '.' + path
: this.$__.fullPath;
}
/**
* Returns this sub-documents parent document.
*
* @api public
*/
EmbeddedDocument.prototype.parent = function () {
return this.__parent;
}
/**
* Returns this sub-documents parent array.
*
* @api public
*/
EmbeddedDocument.prototype.parentArray = function () {
return this.__parentArray;
}
/*!
* Module exports.
*/
module.exports = EmbeddedDocument;

13
node_modules/mongoose/lib/types/index.js generated vendored Normal file
View File

@ -0,0 +1,13 @@
/*!
* Module exports.
*/
exports.Array = require('./array');
exports.Buffer = require('./buffer');
exports.Document = // @deprecate
exports.Embedded = require('./embedded');
exports.DocumentArray = require('./documentarray');
exports.ObjectId = require('./objectid');

43
node_modules/mongoose/lib/types/objectid.js generated vendored Normal file
View File

@ -0,0 +1,43 @@
/*!
* Access driver.
*/
var driver = global.MONGOOSE_DRIVER_PATH || '../drivers/node-mongodb-native';
/**
* ObjectId type constructor
*
* ####Example
*
* var id = new mongoose.Types.ObjectId;
*
* @constructor ObjectId
*/
var ObjectId = require(driver + '/objectid');
module.exports = ObjectId;
/**
* Creates an ObjectId from `str`
*
* @param {ObjectId|HexString} str
* @static fromString
* @receiver ObjectId
* @return {ObjectId}
* @api private
*/
ObjectId.fromString;
/**
* Converts `oid` to a string.
*
* @param {ObjectId} oid ObjectId instance
* @static toString
* @receiver ObjectId
* @return {String}
* @api private
*/
ObjectId.toString;

671
node_modules/mongoose/lib/utils.js generated vendored Normal file
View File

@ -0,0 +1,671 @@
/*!
* Module dependencies.
*/
var ReadPref = require('mongodb').ReadPreference
, ObjectId = require('./types/objectid')
, cloneRegExp = require('regexp-clone')
, sliced = require('sliced')
, mpath = require('mpath')
, ms = require('ms')
, MongooseBuffer
, MongooseArray
, Document
/*!
* Produces a collection name from model `name`.
*
* @param {String} name a model name
* @return {String} a collection name
* @api private
*/
exports.toCollectionName = function (name) {
if ('system.profile' === name) return name;
if ('system.indexes' === name) return name;
return pluralize(name.toLowerCase());
};
/**
* Pluralization rules.
*
* These rules are applied while processing the argument to `toCollectionName`.
*
* @deprecated remove in 4.x gh-1350
*/
exports.pluralization = [
[/(m)an$/gi, '$1en'],
[/(pe)rson$/gi, '$1ople'],
[/(child)$/gi, '$1ren'],
[/^(ox)$/gi, '$1en'],
[/(ax|test)is$/gi, '$1es'],
[/(octop|vir)us$/gi, '$1i'],
[/(alias|status)$/gi, '$1es'],
[/(bu)s$/gi, '$1ses'],
[/(buffal|tomat|potat)o$/gi, '$1oes'],
[/([ti])um$/gi, '$1a'],
[/sis$/gi, 'ses'],
[/(?:([^f])fe|([lr])f)$/gi, '$1$2ves'],
[/(hive)$/gi, '$1s'],
[/([^aeiouy]|qu)y$/gi, '$1ies'],
[/(x|ch|ss|sh)$/gi, '$1es'],
[/(matr|vert|ind)ix|ex$/gi, '$1ices'],
[/([m|l])ouse$/gi, '$1ice'],
[/(quiz)$/gi, '$1zes'],
[/s$/gi, 's'],
[/$/gi, 's']
];
var rules = exports.pluralization;
/**
* Uncountable words.
*
* These words are applied while processing the argument to `toCollectionName`.
* @api public
*/
exports.uncountables = [
'advice',
'energy',
'excretion',
'digestion',
'cooperation',
'health',
'justice',
'labour',
'machinery',
'equipment',
'information',
'pollution',
'sewage',
'paper',
'money',
'species',
'series',
'rain',
'rice',
'fish',
'sheep',
'moose',
'deer',
'news',
'expertise',
'status',
'media'
];
var uncountables = exports.uncountables;
/*!
* Pluralize function.
*
* @author TJ Holowaychuk (extracted from _ext.js_)
* @param {String} string to pluralize
* @api private
*/
function pluralize (str) {
var rule, found;
if (!~uncountables.indexOf(str.toLowerCase())){
found = rules.filter(function(rule){
return str.match(rule[0]);
});
if (found[0]) return str.replace(found[0][0], found[0][1]);
}
return str;
};
/*!
* Determines if `a` and `b` are deep equal.
*
* Modified from node/lib/assert.js
*
* @param {any} a a value to compare to `b`
* @param {any} b a value to compare to `a`
* @return {Boolean}
* @api private
*/
exports.deepEqual = function deepEqual (a, b) {
if (a === b) return true;
if (a instanceof Date && b instanceof Date)
return a.getTime() === b.getTime();
if (a instanceof ObjectId && b instanceof ObjectId) {
return a.toString() === b.toString();
}
if (a instanceof RegExp && b instanceof RegExp) {
return a.source == b.source &&
a.ignoreCase == b.ignoreCase &&
a.multiline == b.multiline &&
a.global == b.global;
}
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;
// Handle MongooseNumbers
if (a instanceof Number && b instanceof Number) {
return a.valueOf() === b.valueOf();
}
if (Buffer.isBuffer(a)) {
if (!Buffer.isBuffer(b)) return false;
if (a.length !== b.length) return false;
for (var i = 0, len = a.length; i < len; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
if (isMongooseObject(a)) a = a.toObject();
if (isMongooseObject(b)) b = b.toObject();
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;
};
/*!
* Object clone with Mongoose natives support.
*
* If options.minimize is true, creates a minimal data object. Empty objects and undefined values will not be cloned. This makes the data payload sent to MongoDB as small as possible.
*
* Functions are never cloned.
*
* @param {Object} obj the object to clone
* @param {Object} options
* @return {Object} the cloned object
* @api private
*/
exports.clone = function clone (obj, options) {
if (obj === undefined || obj === null)
return obj;
if (Array.isArray(obj))
return cloneArray(obj, options);
if (isMongooseObject(obj)) {
if (options && options.json && 'function' === typeof obj.toJSON) {
return obj.toJSON(options);
} else {
return obj.toObject(options);
}
}
if (obj.constructor) {
switch (obj.constructor.name) {
case 'Object':
return cloneObject(obj, options);
case 'Date':
return new obj.constructor(+obj);
case 'RegExp':
return cloneRegExp(obj);
default:
// ignore
break;
}
}
if (obj instanceof ObjectId)
return new ObjectId(obj.id);
if (!obj.constructor && exports.isObject(obj)) {
// object created with Object.create(null)
return cloneObject(obj, options);
}
if (obj.valueOf)
return obj.valueOf();
};
var clone = exports.clone;
/*!
* ignore
*/
function cloneObject (obj, options) {
var retainKeyOrder = options && options.retainKeyOrder
, minimize = options && options.minimize
, ret = {}
, hasKeys
, keys
, val
, k
, i
if (retainKeyOrder) {
for (k in obj) {
val = clone(obj[k], options);
if (!minimize || ('undefined' !== typeof val)) {
hasKeys || (hasKeys = true);
ret[k] = val;
}
}
} else {
// faster
keys = Object.keys(obj);
i = keys.length;
while (i--) {
k = keys[i];
val = clone(obj[k], options);
if (!minimize || ('undefined' !== typeof val)) {
if (!hasKeys) hasKeys = true;
ret[k] = val;
}
}
}
return minimize
? hasKeys && ret
: ret;
};
function cloneArray (arr, options) {
var ret = [];
for (var i = 0, l = arr.length; i < l; i++)
ret.push(clone(arr[i], options));
return ret;
};
/*!
* Shallow copies defaults into options.
*
* @param {Object} defaults
* @param {Object} options
* @return {Object} the merged object
* @api private
*/
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;
};
/*!
* Generates a random string
*
* @api private
*/
exports.random = function () {
return Math.random().toString().substr(3);
};
/*!
* Merges `from` into `to` without overwriting existing properties.
*
* @param {Object} to
* @param {Object} from
* @api private
*/
exports.merge = function merge (to, from) {
var keys = Object.keys(from)
, i = keys.length
, key
while (i--) {
key = keys[i];
if ('undefined' === typeof to[key]) {
to[key] = from[key];
} else {
if (exports.isObject(from[key])) {
merge(to[key], from[key]);
} else {
to[key] = from[key];
}
}
}
};
/*!
* toString helper
*/
var toString = Object.prototype.toString;
/*!
* Determines if `arg` is an object.
*
* @param {Object|Array|String|Function|RegExp|any} arg
* @api private
* @return {Boolean}
*/
exports.isObject = function (arg) {
return '[object Object]' == toString.call(arg);
}
/*!
* A faster Array.prototype.slice.call(arguments) alternative
* @api private
*/
exports.args = sliced;
/*!
* process.nextTick helper.
*
* Wraps `callback` in a try/catch + nextTick.
*
* node-mongodb-native has a habit of state corruption when an error is immediately thrown from within a collection callback.
*
* @param {Function} callback
* @api private
*/
exports.tick = function tick (callback) {
if ('function' !== typeof callback) return;
return function () {
try {
callback.apply(this, arguments);
} catch (err) {
// only nextTick on err to get out of
// the event loop and avoid state corruption.
process.nextTick(function () {
throw err;
});
}
}
}
/*!
* Returns if `v` is a mongoose object that has a `toObject()` method we can use.
*
* This is for compatibility with libs like Date.js which do foolish things to Natives.
*
* @param {any} v
* @api private
*/
exports.isMongooseObject = function (v) {
Document || (Document = require('./document'));
MongooseArray || (MongooseArray = require('./types').Array);
MongooseBuffer || (MongooseBuffer = require('./types').Buffer);
return v instanceof Document ||
v instanceof MongooseArray ||
v instanceof MongooseBuffer
}
var isMongooseObject = exports.isMongooseObject;
/*!
* Converts `expires` options of index objects to `expiresAfterSeconds` options for MongoDB.
*
* @param {Object} object
* @api private
*/
exports.expires = function expires (object) {
if (!(object && 'Object' == object.constructor.name)) return;
if (!('expires' in object)) return;
var when;
if ('string' != typeof object.expires) {
when = object.expires;
} else {
when = Math.round(ms(object.expires) / 1000);
}
object.expireAfterSeconds = when;
delete object.expires;
}
/*!
* Converts arguments to ReadPrefs the driver
* can understand.
*
* @TODO move this into the driver layer
* @param {String|Array} pref
* @param {Array} [tags]
*/
exports.readPref = function readPref (pref, tags) {
if (Array.isArray(pref)) {
tags = pref[1];
pref = pref[0];
}
switch (pref) {
case 'p':
pref = 'primary';
break;
case 'pp':
pref = 'primaryPreferred';
break;
case 's':
pref = 'secondary';
break;
case 'sp':
pref = 'secondaryPreferred';
break;
case 'n':
pref = 'nearest';
break;
}
return new ReadPref(pref, tags);
}
/*!
* Populate options constructor
*/
function PopulateOptions (path, select, match, options, model) {
this.path = path;
this.match = match;
this.select = select;
this.options = options;
this.model = model;
this._docs = {};
}
// make it compatible with utils.clone
PopulateOptions.prototype.constructor = Object;
// expose
exports.PopulateOptions = PopulateOptions;
/*!
* populate helper
*/
exports.populate = function populate (path, select, model, match, options) {
// The order of select/conditions args is opposite Model.find but
// necessary to keep backward compatibility (select could be
// an array, string, or object literal).
// might have passed an object specifying all arguments
if (1 === arguments.length) {
if (path instanceof PopulateOptions) {
return [path];
}
if (Array.isArray(path)) {
return path.map(function(o){
return exports.populate(o)[0];
});
}
if (exports.isObject(path)) {
match = path.match;
options = path.options;
select = path.select;
model = path.model;
path = path.path;
}
} else if ('string' !== typeof model) {
options = match;
match = model;
model = undefined;
}
if ('string' != typeof path) {
throw new TypeError('utils.populate: invalid path. Expected string. Got typeof `' + typeof path + '`');
}
var ret = [];
var paths = path.split(' ');
for (var i = 0; i < paths.length; ++i) {
ret.push(new PopulateOptions(paths[i], select, match, options, model));
}
return ret;
}
/*!
* Return the value of `obj` at the given `path`.
*
* @param {String} path
* @param {Object} obj
*/
exports.getValue = function (path, obj, map) {
return mpath.get(path, obj, '_doc', map);
}
/*!
* Sets the value of `obj` at the given `path`.
*
* @param {String} path
* @param {Anything} val
* @param {Object} obj
*/
exports.setValue = function (path, val, obj, map) {
mpath.set(path, val, obj, '_doc', map);
}
/*!
* Returns an array of values from object `o`.
*
* @param {Object} o
* @return {Array}
* @private
*/
exports.object = {};
exports.object.vals = function vals (o) {
var keys = Object.keys(o)
, i = keys.length
, ret = [];
while (i--) {
ret.push(o[keys[i]]);
}
return ret;
}
/*!
* @see exports.options
*/
exports.object.shallowCopy = exports.options;
/*!
* Safer helper for hasOwnProperty checks
*
* @param {Object} obj
* @param {String} prop
*/
exports.object.hasOwnProperty = function (obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
/*!
* Determine if `val` is null or undefined
*
* @return {Boolean}
*/
exports.isNullOrUndefined = function (val) {
return null == val
}
/*!
* ignore
*/
exports.array = {};
/*!
* Flattens an array.
*
* [ 1, [ 2, 3, [4] ]] -> [1,2,3,4]
*
* @param {Array} arr
* @param {Function} [filter] If passed, will be invoked with each item in the array. If `filter` returns a falsey value, the item will not be included in the results.
* @return {Array}
* @private
*/
exports.array.flatten = function flatten (arr, filter, ret) {
ret || (ret = []);
arr.forEach(function (item) {
if (Array.isArray(item)) {
flatten(item, filter, ret);
} else {
if (!filter || filter(item)) {
ret.push(item);
}
}
});
return ret;
}

103
node_modules/mongoose/lib/virtualtype.js generated vendored Normal file
View File

@ -0,0 +1,103 @@
/**
* VirtualType constructor
*
* This is what mongoose uses to define virtual attributes via `Schema.prototype.virtual`.
*
* ####Example:
*
* var fullname = schema.virtual('fullname');
* fullname instanceof mongoose.VirtualType // true
*
* @parma {Object} options
* @api public
*/
function VirtualType (options, name) {
this.path = name;
this.getters = [];
this.setters = [];
this.options = options || {};
}
/**
* Defines a getter.
*
* ####Example:
*
* var virtual = schema.virtual('fullname');
* virtual.get(function () {
* return this.name.first + ' ' + this.name.last;
* });
*
* @param {Function} fn
* @return {VirtualType} this
* @api public
*/
VirtualType.prototype.get = function (fn) {
this.getters.push(fn);
return this;
};
/**
* Defines a setter.
*
* ####Example:
*
* var virtual = schema.virtual('fullname');
* virtual.set(function (v) {
* var parts = v.split(' ');
* this.name.first = parts[0];
* this.name.last = parts[1];
* });
*
* @param {Function} fn
* @return {VirtualType} this
* @api public
*/
VirtualType.prototype.set = function (fn) {
this.setters.push(fn);
return this;
};
/**
* Applies getters to `value` using optional `scope`.
*
* @param {Object} value
* @param {Object} scope
* @return {any} the value after applying all getters
* @api public
*/
VirtualType.prototype.applyGetters = function (value, scope) {
var v = value;
for (var l = this.getters.length - 1; l >= 0; l--) {
v = this.getters[l].call(scope, v, this);
}
return v;
};
/**
* Applies setters to `value` using optional `scope`.
*
* @param {Object} value
* @param {Object} scope
* @return {any} the value after applying all setters
* @api public
*/
VirtualType.prototype.applySetters = function (value, scope) {
var v = value;
for (var l = this.setters.length - 1; l >= 0; l--) {
v = this.setters[l].call(scope, v, this);
}
return v;
};
/*!
* exports
*/
module.exports = VirtualType;

2
node_modules/mongoose/node_modules/hooks/.npmignore generated vendored Normal file
View File

@ -0,0 +1,2 @@
**.swp
node_modules

9
node_modules/mongoose/node_modules/hooks/Makefile generated vendored Normal file
View File

@ -0,0 +1,9 @@
test:
@NODE_ENV=test ./node_modules/expresso/bin/expresso \
$(TESTFLAGS) \
./test.js
test-cov:
@TESTFLAGS=--cov $(MAKE) test
.PHONY: test test-cov

306
node_modules/mongoose/node_modules/hooks/README.md generated vendored Normal file
View File

@ -0,0 +1,306 @@
hooks
============
Add pre and post middleware hooks to your JavaScript methods.
## Installation
npm install hooks
## Motivation
Suppose you have a JavaScript object with a `save` method.
It would be nice to be able to declare code that runs before `save` and after `save`.
For example, you might want to run validation code before every `save`,
and you might want to dispatch a job to a background job queue after `save`.
One might have an urge to hard code this all into `save`, but that turns out to
couple all these pieces of functionality (validation, save, and job creation) more
tightly than is necessary. For example, what if someone does not want to do background
job creation after the logical save?
It is nicer to tack on functionality using what we call `pre` and `post` hooks. These
are functions that you define and that you direct to execute before or after particular
methods.
## Example
We can use `hooks` to add validation and background jobs in the following way:
var hooks = require('hooks')
, Document = require('./path/to/some/document/constructor');
// Add hooks' methods: `hook`, `pre`, and `post`
for (var k in hooks) {
Document[k] = hooks[k];
}
// Define a new method that is able to invoke pre and post middleware
Document.hook('save', Document.prototype.save);
// Define a middleware function to be invoked before 'save'
Document.pre('save', function validate (next) {
// The `this` context inside of `pre` and `post` functions
// is the Document instance
if (this.isValid()) next(); // next() passes control to the next middleware
// or to the target method itself
else next(new Error("Invalid")); // next(error) invokes an error callback
});
// Define a middleware function to be invoked after 'save'
Document.post('save', function createJob () {
this.sendToBackgroundQueue();
});
If you already have defined `Document.prototype` methods for which you want pres and posts,
then you do not need to explicitly invoke `Document.hook(...)`. Invoking `Document.pre(methodName, fn)`
or `Document.post(methodName, fn)` will automatically and lazily change `Document.prototype[methodName]`
so that it plays well with `hooks`. An equivalent way to implement the previous example is:
```javascript
var hooks = require('hooks')
, Document = require('./path/to/some/document/constructor');
// Add hooks' methods: `hook`, `pre`, and `post`
for (var k in hooks) {
Document[k] = hooks[k];
}
Document.prototype.save = function () {
// ...
};
// Define a middleware function to be invoked before 'save'
Document.pre('save', function validate (next) {
// The `this` context inside of `pre` and `post` functions
// is the Document instance
if (this.isValid()) next(); // next() passes control to the next middleware
// or to the target method itself
else next(new Error("Invalid")); // next(error) invokes an error callback
});
// Define a middleware function to be invoked after 'save'
Document.post('save', function createJob () {
this.sendToBackgroundQueue();
});
```
## Pres and Posts as Middleware
We structure pres and posts as middleware to give you maximum flexibility:
1. You can define **multiple** pres (or posts) for a single method.
2. These pres (or posts) are then executed as a chain of methods.
3. Any functions in this middleware chain can choose to halt the chain's execution by `next`ing an Error from that middleware function. If this occurs, then none of the other middleware in the chain will execute, and the main method (e.g., `save`) will not execute. This is nice, for example, when we don't want a document to save if it is invalid.
## Defining multiple pres (or posts)
`pre` is chainable, so you can define multiple pres via:
Document.pre('save', function (next, halt) {
console.log("hello");
}).pre('save', function (next, halt) {
console.log("world");
});
As soon as one pre finishes executing, the next one will be invoked, and so on.
## Error Handling
You can define a default error handler by passing a 2nd function as the 3rd argument to `hook`:
Document.hook('set', function (path, val) {
this[path] = val;
}, function (err) {
// Handler the error here
console.error(err);
});
Then, we can pass errors to this handler from a pre or post middleware function:
Document.pre('set', function (next, path, val) {
next(new Error());
});
If you do not set up a default handler, then `hooks` makes the default handler that just throws the `Error`.
The default error handler can be over-rided on a per method invocation basis.
If the main method that you are surrounding with pre and post middleware expects its last argument to be a function
with callback signature `function (error, ...)`, then that callback becomes the error handler, over-riding the default
error handler you may have set up.
```javascript
Document.hook('save', function (callback) {
// Save logic goes here
...
});
var doc = new Document();
doc.save( function (err, saved) {
// We can pass err via `next` in any of our pre or post middleware functions
if (err) console.error(err);
// Rest of callback logic follows ...
});
```
## Mutating Arguments via Middleware
`pre` and `post` middleware can also accept the intended arguments for the method
they augment. This is useful if you want to mutate the arguments before passing
them along to the next middleware and eventually pass a mutated arguments list to
the main method itself.
As a simple example, let's define a method `set` that just sets a key, value pair.
If we want to namespace the key, we can do so by adding a `pre` middleware hook
that runs before `set`, alters the arguments by namespacing the `key` argument, and passes them onto `set`:
Document.hook('set', function (key, val) {
this[key] = val;
});
Document.pre('set', function (next, key, val) {
next('namespace-' + key, val);
});
var doc = new Document();
doc.set('hello', 'world');
console.log(doc.hello); // undefined
console.log(doc['namespace-hello']); // 'world'
As you can see above, we pass arguments via `next`.
If you are not mutating the arguments, then you can pass zero arguments
to `next`, and the next middleware function will still have access
to the arguments.
Document.hook('set', function (key, val) {
this[key] = val;
});
Document.pre('set', function (next, key, val) {
// I have access to key and val here
next(); // We don't need to pass anything to next
});
Document.pre('set', function (next, key, val) {
// And I still have access to the original key and val here
next();
});
Finally, you can add arguments that downstream middleware can also see:
// Note that in the definition of `set`, there is no 3rd argument, options
Document.hook('set', function (key, val) {
// But...
var options = arguments[2]; // ...I have access to an options argument
// because of pre function pre2 (defined below)
console.log(options); // '{debug: true}'
this[key] = val;
});
Document.pre('set', function pre1 (next, key, val) {
// I only have access to key and val arguments
console.log(arguments.length); // 3
next(key, val, {debug: true});
});
Document.pre('set', function pre2 (next, key, val, options) {
console.log(arguments.length); // 4
console.log(options); // '{ debug: true}'
next();
});
Document.pre('set', function pre3 (next, key, val, options) {
// I still have access to key, val, AND the options argument introduced via the preceding middleware
console.log(arguments.length); // 4
console.log(options); // '{ debug: true}'
next();
});
var doc = new Document()
doc.set('hey', 'there');
## Parallel `pre` middleware
All middleware up to this point has been "serial" middleware -- i.e., middleware whose logic
is executed as a serial chain.
Some scenarios call for parallel middleware -- i.e., middleware that can wait for several
asynchronous services at once to respond.
For instance, you may only want to save a Document only after you have checked
that the Document is valid according to two different remote services.
We accomplish asynchronous middleware by adding a second kind of flow control callback
(the only flow control callback so far has been `next`), called `done`.
- `next` passes control to the next middleware in the chain
- `done` keeps track of how many parallel middleware have invoked `done` and passes
control to the target method when ALL parallel middleware have invoked `done`. If
you pass an `Error` to `done`, then the error is handled, and the main method that is
wrapped by pres and posts will not get invoked.
We declare pre middleware that is parallel by passing a 3rd boolean argument to our `pre`
definition method.
We illustrate via the parallel validation example mentioned above:
Document.hook('save', function targetFn (callback) {
// Save logic goes here
// ...
// This only gets run once the two `done`s are both invoked via preOne and preTwo.
});
// true marks this as parallel middleware
Document.pre('save', true, function preOne (next, doneOne, callback) {
remoteServiceOne.validate(this.serialize(), function (err, isValid) {
// The code in here will probably be run after the `next` below this block
// and could possibly be run after the console.log("Hola") in `preTwo
if (err) return doneOne(err);
if (isValid) doneOne();
});
next(); // Pass control to the next middleware
});
// We will suppose that we need 2 different remote services to validate our document
Document.pre('save', true, function preTwo (next, doneTwo, callback) {
remoteServiceTwo.validate(this.serialize(), function (err, isValid) {
if (err) return doneTwo(err);
if (isValid) doneTwo();
});
next();
});
// While preOne and preTwo are parallel, preThree is a serial pre middleware
Document.pre('save', function preThree (next, callback) {
next();
});
var doc = new Document();
doc.save( function (err, doc) {
// Do stuff with the saved doc here...
});
In the above example, flow control may happen in the following way:
(1) doc.save -> (2) preOne --(next)--> (3) preTwo --(next)--> (4) preThree --(next)--> (wait for dones to invoke) -> (5) doneTwo -> (6) doneOne -> (7) targetFn
So what's happening is that:
1. You call `doc.save(...)`
2. First, your preOne middleware gets executed. It makes a remote call to the validation service and `next()`s to the preTwo middleware.
3. Now, your preTwo middleware gets executed. It makes a remote call to another validation service and `next()`s to the preThree middleware.
4. Your preThree middleware gets executed. It immediately `next()`s. But nothing else gets executing until both `doneOne` and `doneTwo` are invoked inside the callbacks handling the response from the two valiation services.
5. We will suppose that validation remoteServiceTwo returns a response to us first. In this case, we call `doneTwo` inside the callback to remoteServiceTwo.
6. Some fractions of a second later, remoteServiceOne returns a response to us. In this case, we call `doneOne` inside the callback to remoteServiceOne.
7. `hooks` implementation keeps track of how many parallel middleware has been defined per target function. It detects that both asynchronous pre middlewares (`preOne` and `preTwo`) have finally called their `done` functions (`doneOne` and `doneTwo`), so the implementation finally invokes our `targetFn` (i.e., our core `save` business logic).
## Removing Pres
You can remove a particular pre associated with a hook:
Document.pre('set', someFn);
Document.removePre('set', someFn);
And you can also remove all pres associated with a hook:
Document.removePre('set'); // Removes all declared `pre`s on the hook 'set'
## Tests
To run the tests:
make test
### Contributors
- [Brian Noguchi](https://github.com/bnoguchi)
### License
MIT License
---
### Author
Brian Noguchi

134
node_modules/mongoose/node_modules/hooks/hooks.alt.js generated vendored Normal file
View File

@ -0,0 +1,134 @@
/**
* Hooks are useful if we want to add a method that automatically has `pre` and `post` hooks.
* For example, it would be convenient to have `pre` and `post` hooks for `save`.
* _.extend(Model, mixins.hooks);
* Model.hook('save', function () {
* console.log('saving');
* });
* Model.pre('save', function (next, done) {
* console.log('about to save');
* next();
* });
* Model.post('save', function (next, done) {
* console.log('saved');
* next();
* });
*
* var m = new Model();
* m.save();
* // about to save
* // saving
* // saved
*/
// TODO Add in pre and post skipping options
module.exports = {
/**
* Declares a new hook to which you can add pres and posts
* @param {String} name of the function
* @param {Function} the method
* @param {Function} the error handler callback
*/
hook: function (name, fn, err) {
if (arguments.length === 1 && typeof name === 'object') {
for (var k in name) { // `name` is a hash of hookName->hookFn
this.hook(k, name[k]);
}
return;
}
if (!err) err = fn;
var proto = this.prototype || this
, pres = proto._pres = proto._pres || {}
, posts = proto._posts = proto._posts || {};
pres[name] = pres[name] || [];
posts[name] = posts[name] || [];
function noop () {}
proto[name] = function () {
var self = this
, pres = this._pres[name]
, posts = this._posts[name]
, numAsyncPres = 0
, hookArgs = [].slice.call(arguments)
, preChain = pres.map( function (pre, i) {
var wrapper = function () {
if (arguments[0] instanceof Error)
return err(arguments[0]);
if (numAsyncPres) {
// arguments[1] === asyncComplete
if (arguments.length)
hookArgs = [].slice.call(arguments, 2);
pre.apply(self,
[ preChain[i+1] || allPresInvoked,
asyncComplete
].concat(hookArgs)
);
} else {
if (arguments.length)
hookArgs = [].slice.call(arguments);
pre.apply(self,
[ preChain[i+1] || allPresDone ].concat(hookArgs));
}
}; // end wrapper = function () {...
if (wrapper.isAsync = pre.isAsync)
numAsyncPres++;
return wrapper;
}); // end posts.map(...)
function allPresInvoked () {
if (arguments[0] instanceof Error)
err(arguments[0]);
}
function allPresDone () {
if (arguments[0] instanceof Error)
return err(arguments[0]);
if (arguments.length)
hookArgs = [].slice.call(arguments);
fn.apply(self, hookArgs);
var postChain = posts.map( function (post, i) {
var wrapper = function () {
if (arguments[0] instanceof Error)
return err(arguments[0]);
if (arguments.length)
hookArgs = [].slice.call(arguments);
post.apply(self,
[ postChain[i+1] || noop].concat(hookArgs));
}; // end wrapper = function () {...
return wrapper;
}); // end posts.map(...)
if (postChain.length) postChain[0]();
}
if (numAsyncPres) {
complete = numAsyncPres;
function asyncComplete () {
if (arguments[0] instanceof Error)
return err(arguments[0]);
--complete || allPresDone.call(this);
}
}
(preChain[0] || allPresDone)();
};
return this;
},
pre: function (name, fn, isAsync) {
var proto = this.prototype
, pres = proto._pres = proto._pres || {};
if (fn.isAsync = isAsync) {
this.prototype[name].numAsyncPres++;
}
(pres[name] = pres[name] || []).push(fn);
return this;
},
post: function (name, fn, isAsync) {
var proto = this.prototype
, posts = proto._posts = proto._posts || {};
(posts[name] = posts[name] || []).push(fn);
return this;
}
};

161
node_modules/mongoose/node_modules/hooks/hooks.js generated vendored Normal file
View File

@ -0,0 +1,161 @@
// TODO Add in pre and post skipping options
module.exports = {
/**
* Declares a new hook to which you can add pres and posts
* @param {String} name of the function
* @param {Function} the method
* @param {Function} the error handler callback
*/
hook: function (name, fn, errorCb) {
if (arguments.length === 1 && typeof name === 'object') {
for (var k in name) { // `name` is a hash of hookName->hookFn
this.hook(k, name[k]);
}
return;
}
var proto = this.prototype || this
, pres = proto._pres = proto._pres || {}
, posts = proto._posts = proto._posts || {};
pres[name] = pres[name] || [];
posts[name] = posts[name] || [];
proto[name] = function () {
var self = this
, hookArgs // arguments eventually passed to the hook - are mutable
, lastArg = arguments[arguments.length-1]
, pres = this._pres[name]
, posts = this._posts[name]
, _total = pres.length
, _current = -1
, _asyncsLeft = proto[name].numAsyncPres
, _next = function () {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var _args = Array.prototype.slice.call(arguments)
, currPre
, preArgs;
if (_args.length && !(arguments[0] == null && typeof lastArg === 'function'))
hookArgs = _args;
if (++_current < _total) {
currPre = pres[_current]
if (currPre.isAsync && currPre.length < 2)
throw new Error("Your pre must have next and done arguments -- e.g., function (next, done, ...)");
if (currPre.length < 1)
throw new Error("Your pre must have a next argument -- e.g., function (next, ...)");
preArgs = (currPre.isAsync
? [once(_next), once(_asyncsDone)]
: [once(_next)]).concat(hookArgs);
return currPre.apply(self, preArgs);
} else if (!proto[name].numAsyncPres) {
return _done.apply(self, hookArgs);
}
}
, _done = function () {
var args_ = Array.prototype.slice.call(arguments)
, ret, total_, current_, next_, done_, postArgs;
if (_current === _total) {
ret = fn.apply(self, args_);
total_ = posts.length;
current_ = -1;
next_ = function () {
if (arguments[0] instanceof Error) {
return handleError(arguments[0]);
}
var args_ = Array.prototype.slice.call(arguments, 1)
, currPost
, postArgs;
if (args_.length) hookArgs = args_;
if (++current_ < total_) {
currPost = posts[current_]
if (currPost.length < 1)
throw new Error("Your post must have a next argument -- e.g., function (next, ...)");
postArgs = [once(next_)].concat(hookArgs);
return currPost.apply(self, postArgs);
}
};
if (total_) return next_();
return ret;
}
};
if (_asyncsLeft) {
function _asyncsDone (err) {
if (err && err instanceof Error) {
return handleError(err);
}
--_asyncsLeft || _done.apply(self, hookArgs);
}
}
function handleError (err) {
if ('function' == typeof lastArg)
return lastArg(err);
if (errorCb) return errorCb.call(self, err);
throw err;
}
return _next.apply(this, arguments);
};
proto[name].numAsyncPres = 0;
return this;
},
pre: function (name, isAsync, fn, errorCb) {
if ('boolean' !== typeof arguments[1]) {
errorCb = fn;
fn = isAsync;
isAsync = false;
}
var proto = this.prototype || this
, pres = proto._pres = proto._pres || {};
this._lazySetupHooks(proto, name, errorCb);
if (fn.isAsync = isAsync) {
proto[name].numAsyncPres++;
}
(pres[name] = pres[name] || []).push(fn);
return this;
},
post: function (name, isAsync, fn) {
if (arguments.length === 2) {
fn = isAsync;
isAsync = false;
}
var proto = this.prototype || this
, posts = proto._posts = proto._posts || {};
this._lazySetupHooks(proto, name);
(posts[name] = posts[name] || []).push(fn);
return this;
},
removePre: function (name, fnToRemove) {
var proto = this.prototype || this
, pres = proto._pres || (proto._pres || {});
if (!pres[name]) return this;
if (arguments.length === 1) {
// Remove all pre callbacks for hook `name`
pres[name].length = 0;
} else {
pres[name] = pres[name].filter( function (currFn) {
return currFn !== fnToRemove;
});
}
return this;
},
_lazySetupHooks: function (proto, methodName, errorCb) {
if ('undefined' === typeof proto[methodName].numAsyncPres) {
this.hook(methodName, proto[methodName], errorCb);
}
}
};
function once (fn, scope) {
return function fnWrapper () {
if (fnWrapper.hookCalled) return;
fnWrapper.hookCalled = true;
fn.apply(scope, arguments);
};
}

50
node_modules/mongoose/node_modules/hooks/package.json generated vendored Normal file

File diff suppressed because one or more lines are too long

691
node_modules/mongoose/node_modules/hooks/test.js generated vendored Normal file
View File

@ -0,0 +1,691 @@
var hooks = require('./hooks')
, should = require('should')
, assert = require('assert')
, _ = require('underscore');
// TODO Add in test for making sure all pres get called if pre is defined directly on an instance.
// TODO Test for calling `done` twice or `next` twice in the same function counts only once
module.exports = {
'should be able to assign multiple hooks at once': function () {
var A = function () {};
_.extend(A, hooks);
A.hook({
hook1: function (a) {},
hook2: function (b) {}
});
var a = new A();
assert.equal(typeof a.hook1, 'function');
assert.equal(typeof a.hook2, 'function');
},
'should run without pres and posts when not present': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
var a = new A();
a.save();
a.value.should.equal(1);
},
'should run with pres when present': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.preValue = 2;
next();
});
var a = new A();
a.save();
a.value.should.equal(1);
a.preValue.should.equal(2);
},
'should run with posts when present': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.post('save', function (next) {
this.value = 2;
next();
});
var a = new A();
a.save();
a.value.should.equal(2);
},
'should run pres and posts when present': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.preValue = 2;
next();
});
A.post('save', function (next) {
this.value = 3;
next();
});
var a = new A();
a.save();
a.value.should.equal(3);
a.preValue.should.equal(2);
},
'should run posts after pres': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.override = 100;
next();
});
A.post('save', function (next) {
this.override = 200;
next();
});
var a = new A();
a.save();
a.value.should.equal(1);
a.override.should.equal(200);
},
'should not run a hook if a pre fails': function () {
var A = function () {};
_.extend(A, hooks);
var counter = 0;
A.hook('save', function () {
this.value = 1;
}, function (err) {
counter++;
});
A.pre('save', true, function (next, done) {
next(new Error());
});
var a = new A();
a.save();
counter.should.equal(1);
assert.equal(typeof a.value, 'undefined');
},
'should be able to run multiple pres': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.v1 = 1;
next();
}).pre('save', function (next) {
this.v2 = 2;
next();
});
var a = new A();
a.save();
a.v1.should.equal(1);
a.v2.should.equal(2);
},
'should run multiple pres until a pre fails and not call the hook': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
}, function (err) {});
A.pre('save', function (next) {
this.v1 = 1;
next();
}).pre('save', function (next) {
next(new Error());
}).pre('save', function (next) {
this.v3 = 3;
next();
});
var a = new A();
a.save();
a.v1.should.equal(1);
assert.equal(typeof a.v3, 'undefined');
assert.equal(typeof a.value, 'undefined');
},
'should be able to run multiple posts': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.post('save', function (next) {
this.value = 2;
next();
}).post('save', function (next) {
this.value = 3.14;
next();
}).post('save', function (next) {
this.v3 = 3;
next();
});
var a = new A();
a.save();
assert.equal(a.value, 3.14);
assert.equal(a.v3, 3);
},
'should run only posts up until an error': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
}, function (err) {});
A.post('save', function (next) {
this.value = 2;
next();
}).post('save', function (next) {
this.value = 3;
next(new Error());
}).post('save', function (next) {
this.value = 4;
next();
});
var a = new A();
a.save();
a.value.should.equal(3);
},
"should fall back first to the hook method's last argument as the error handler if it is a function of arity 1 or 2": function () {
var A = function () {};
_.extend(A, hooks);
var counter = 0;
A.hook('save', function (callback) {
this.value = 1;
});
A.pre('save', true, function (next, done) {
next(new Error());
});
var a = new A();
a.save( function (err) {
if (err instanceof Error) counter++;
});
counter.should.equal(1);
should.deepEqual(undefined, a.value);
},
'should fall back second to the default error handler if specified': function () {
var A = function () {};
_.extend(A, hooks);
var counter = 0;
A.hook('save', function (callback) {
this.value = 1;
}, function (err) {
if (err instanceof Error) counter++;
});
A.pre('save', true, function (next, done) {
next(new Error());
});
var a = new A();
a.save();
counter.should.equal(1);
should.deepEqual(undefined, a.value);
},
'fallback default error handler should scope to the object': function () {
var A = function () {
this.counter = 0;
};
_.extend(A, hooks);
var counter = 0;
A.hook('save', function (callback) {
this.value = 1;
}, function (err) {
if (err instanceof Error) this.counter++;
});
A.pre('save', true, function (next, done) {
next(new Error());
});
var a = new A();
a.save();
a.counter.should.equal(1);
should.deepEqual(undefined, a.value);
},
'should fall back last to throwing the error': function () {
var A = function () {};
_.extend(A, hooks);
var counter = 0;
A.hook('save', function (err) {
if (err instanceof Error) return counter++;
this.value = 1;
});
A.pre('save', true, function (next, done) {
next(new Error());
});
var a = new A();
var didCatch = false;
try {
a.save();
} catch (e) {
didCatch = true;
e.should.be.an.instanceof(Error);
counter.should.equal(0);
assert.equal(typeof a.value, 'undefined');
}
didCatch.should.be.true;
},
"should proceed without mutating arguments if `next(null|undefined)` is called in a serial pre, and the last argument of the target method is a callback with node-like signature function (err, obj) {...} or function (err) {...}": function () {
var A = function () {};
_.extend(A, hooks);
var counter = 0;
A.prototype.save = function (callback) {
this.value = 1;
callback();
};
A.pre('save', function (next) {
next(null);
});
A.pre('save', function (next) {
next(undefined);
});
var a = new A();
a.save( function (err) {
if (err instanceof Error) counter++;
else counter--;
});
counter.should.equal(-1);
a.value.should.eql(1);
},
"should proceed with mutating arguments if `next(null|undefined)` is callback in a serial pre, and the last argument of the target method is not a function": function () {
var A = function () {};
_.extend(A, hooks);
A.prototype.set = function (v) {
this.value = v;
};
A.pre('set', function (next) {
next(undefined);
});
A.pre('set', function (next) {
next(null);
});
var a = new A();
a.set(1);
should.strictEqual(null, a.value);
},
'should not run any posts if a pre fails': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 2;
}, function (err) {});
A.pre('save', function (next) {
this.value = 1;
next(new Error());
}).post('save', function (next) {
this.value = 3;
next();
});
var a = new A();
a.save();
a.value.should.equal(1);
},
"can pass the hook's arguments verbatim to pres": function () {
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
this[path] = val;
});
A.pre('set', function (next, path, val) {
path.should.equal('hello');
val.should.equal('world');
next();
});
var a = new A();
a.set('hello', 'world');
a.hello.should.equal('world');
},
// "can pass the hook's arguments as an array to pres": function () {
// // Great for dynamic arity - e.g., slice(...)
// var A = function () {};
// _.extend(A, hooks);
// A.hook('set', function (path, val) {
// this[path] = val;
// });
// A.pre('set', function (next, hello, world) {
// hello.should.equal('hello');
// world.should.equal('world');
// next();
// });
// var a = new A();
// a.set('hello', 'world');
// assert.equal(a.hello, 'world');
// },
"can pass the hook's arguments verbatim to posts": function () {
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
this[path] = val;
});
A.post('set', function (next, path, val) {
path.should.equal('hello');
val.should.equal('world');
next();
});
var a = new A();
a.set('hello', 'world');
assert.equal(a.hello, 'world');
},
// "can pass the hook's arguments as an array to posts": function () {
// var A = function () {};
// _.extend(A, hooks);
// A.hook('set', function (path, val) {
// this[path] = val;
// });
// A.post('set', function (next, halt, args) {
// assert.equal(args[0], 'hello');
// assert.equal(args[1], 'world');
// next();
// });
// var a = new A();
// a.set('hello', 'world');
// assert.equal(a.hello, 'world');
// },
"pres should be able to modify and pass on a modified version of the hook's arguments": function () {
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
this[path] = val;
assert.equal(arguments[2], 'optional');
});
A.pre('set', function (next, path, val) {
next('foo', 'bar');
});
A.pre('set', function (next, path, val) {
assert.equal(path, 'foo');
assert.equal(val, 'bar');
next('rock', 'says', 'optional');
});
A.pre('set', function (next, path, val, opt) {
assert.equal(path, 'rock');
assert.equal(val, 'says');
assert.equal(opt, 'optional');
next();
});
var a = new A();
a.set('hello', 'world');
assert.equal(typeof a.hello, 'undefined');
a.rock.should.equal('says');
},
'posts should see the modified version of arguments if the pres modified them': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
this[path] = val;
});
A.pre('set', function (next, path, val) {
next('foo', 'bar');
});
A.post('set', function (next, path, val) {
path.should.equal('foo');
val.should.equal('bar');
});
var a = new A();
a.set('hello', 'world');
assert.equal(typeof a.hello, 'undefined');
a.foo.should.equal('bar');
},
'should pad missing arguments (relative to expected arguments of the hook) with null': function () {
// Otherwise, with hookFn = function (a, b, next, ),
// if we use hookFn(a), then because the pre functions are of the form
// preFn = function (a, b, next, ), then it actually gets executed with
// preFn(a, next, ), so when we call next() from within preFn, we are actually
// calling ()
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val, opts) {
this[path] = val;
});
A.pre('set', function (next, path, val, opts) {
next('foo', 'bar');
assert.equal(typeof opts, 'undefined');
});
var a = new A();
a.set('hello', 'world');
},
'should not invoke the target method until all asynchronous middleware have invoked dones': function () {
var counter = 0;
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
counter++;
this[path] = val;
counter.should.equal(7);
});
A.pre('set', function (next, path, val) {
counter++;
next();
});
A.pre('set', true, function (next, done, path, val) {
counter++;
setTimeout(function () {
counter++;
done();
}, 1000);
next();
});
A.pre('set', function (next, path, val) {
counter++;
next();
});
A.pre('set', true, function (next, done, path, val) {
counter++;
setTimeout(function () {
counter++;
done();
}, 500);
next();
});
var a = new A();
a.set('hello', 'world');
},
'invoking a method twice should run its async middleware twice': function () {
var counter = 0;
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val) {
this[path] = val;
if (path === 'hello') counter.should.equal(1);
if (path === 'foo') counter.should.equal(2);
});
A.pre('set', true, function (next, done, path, val) {
setTimeout(function () {
counter++;
done();
}, 1000);
next();
});
var a = new A();
a.set('hello', 'world');
a.set('foo', 'bar');
},
'calling the same done multiple times should have the effect of only calling it once': function () {
var A = function () {
this.acked = false;
};
_.extend(A, hooks);
A.hook('ack', function () {
console.log("UH OH, YOU SHOULD NOT BE SEEING THIS");
this.acked = true;
});
A.pre('ack', true, function (next, done) {
next();
done();
done();
});
A.pre('ack', true, function (next, done) {
next();
// Notice that done() is not invoked here
});
var a = new A();
a.ack();
setTimeout( function () {
a.acked.should.be.false;
}, 1000);
},
'calling the same next multiple times should have the effect of only calling it once': function (beforeExit) {
var A = function () {
this.acked = false;
};
_.extend(A, hooks);
A.hook('ack', function () {
console.log("UH OH, YOU SHOULD NOT BE SEEING THIS");
this.acked = true;
});
A.pre('ack', function (next) {
// force a throw to re-exec next()
try {
next(new Error('bam'));
} catch (err) {
next();
}
});
A.pre('ack', function (next) {
next();
});
var a = new A();
a.ack();
beforeExit( function () {
a.acked.should.be.false;
});
},
'asynchronous middleware should be able to pass an error via `done`, stopping the middleware chain': function () {
var counter = 0;
var A = function () {};
_.extend(A, hooks);
A.hook('set', function (path, val, fn) {
counter++;
this[path] = val;
fn(null);
});
A.pre('set', true, function (next, done, path, val, fn) {
setTimeout(function () {
counter++;
done(new Error);
}, 1000);
next();
});
var a = new A();
a.set('hello', 'world', function (err) {
err.should.be.an.instanceof(Error);
should.strictEqual(undefined, a['hello']);
counter.should.eql(1);
});
},
'should be able to remove a particular pre': function () {
var A = function () {}
, preTwo;
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.preValueOne = 2;
next();
});
A.pre('save', preTwo = function (next) {
this.preValueTwo = 4;
next();
});
A.removePre('save', preTwo);
var a = new A();
a.save();
a.value.should.equal(1);
a.preValueOne.should.equal(2);
should.strictEqual(undefined, a.preValueTwo);
},
'should be able to remove all pres associated with a hook': function () {
var A = function () {};
_.extend(A, hooks);
A.hook('save', function () {
this.value = 1;
});
A.pre('save', function (next) {
this.preValueOne = 2;
next();
});
A.pre('save', function (next) {
this.preValueTwo = 4;
next();
});
A.removePre('save');
var a = new A();
a.save();
a.value.should.equal(1);
should.strictEqual(undefined, a.preValueOne);
should.strictEqual(undefined, a.preValueTwo);
},
'#pre should lazily make a method hookable': function () {
var A = function () {};
_.extend(A, hooks);
A.prototype.save = function () {
this.value = 1;
};
A.pre('save', function (next) {
this.preValue = 2;
next();
});
var a = new A();
a.save();
a.value.should.equal(1);
a.preValue.should.equal(2);
},
'#pre lazily making a method hookable should be able to provide a default errorHandler as the last argument': function () {
var A = function () {};
var preValue = "";
_.extend(A, hooks);
A.prototype.save = function () {
this.value = 1;
};
A.pre('save', function (next) {
next(new Error);
}, function (err) {
preValue = 'ERROR';
});
var a = new A();
a.save();
should.strictEqual(undefined, a.value);
preValue.should.equal('ERROR');
},
'#post should lazily make a method hookable': function () {
var A = function () {};
_.extend(A, hooks);
A.prototype.save = function () {
this.value = 1;
};
A.post('save', function (next) {
this.value = 2;
next();
});
var a = new A();
a.save();
a.value.should.equal(2);
},
"a lazy hooks setup should handle errors via a method's last argument, if it's a callback": function () {
var A = function () {};
_.extend(A, hooks);
A.prototype.save = function (fn) {};
A.pre('save', function (next) {
next(new Error("hi there"));
});
var a = new A();
a.save( function (err) {
err.should.be.an.instanceof(Error);
});
}
};

View File

@ -0,0 +1,5 @@
language: node_js
node_js:
- 0.6
- 0.8
- 0.10 # development version of 0.8, may be unstable

View File

@ -0,0 +1,23 @@
## Contributing to the driver
### Bugfixes
- Before starting to write code, look for existing [tickets](https://github.com/mongodb/node-mongodb-native/issues) or [create one](https://github.com/mongodb/node-mongodb-native/issues/new) for your specific issue. That way you avoid working on something that might not be of interest or that has been addressed already in a different branch.
- Fork the [repo](https://github.com/mongodb/node-mongodb-native) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
- Follow the general coding style of the rest of the project:
- 2 space tabs
- no trailing whitespace
- comma last
- inline documentation for new methods, class members, etc
- 0 space between conditionals/functions, and their parenthesis and curly braces
- `if(..) {`
- `for(..) {`
- `while(..) {`
- `function(err) {`
- Write tests and make sure they pass (execute `make test` from the cmd line to run the test suite).
### Documentation
To contribute to the [API documentation](http://mongodb.github.com/node-mongodb-native/) just make your changes to the inline documentation of the appropriate [source code](https://github.com/mongodb/node-mongodb-native/tree/master/docs) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute `make generate_docs`. Make sure you have the python documentation framework sphinx installed `easy_install sphinx`. The docs are generated under `docs/build'. If all looks good, submit a [pull request](https://help.github.com/articles/using-pull-requests/) to the master branch with your changes.

201
node_modules/mongoose/node_modules/mongodb/LICENSE generated vendored Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

28
node_modules/mongoose/node_modules/mongodb/Makefile generated vendored Normal file
View File

@ -0,0 +1,28 @@
NODE = node
NPM = npm
NODEUNIT = node_modules/nodeunit/bin/nodeunit
DOX = node_modules/dox/bin/dox
name = all
total: build_native
test_functional:
node test/runner.js -t functional
test_ssl:
node test/runner.js -t ssl
test_replicaset:
node test/runner.js -t replicaset
test_sharded:
node test/runner.js -t sharded
test_auth:
node test/runner.js -t auth
generate_docs:
$(NODE) dev/tools/build-docs.js
make --directory=./docs/sphinx-docs --file=Makefile html
.PHONY: total

421
node_modules/mongoose/node_modules/mongodb/Readme.md generated vendored Normal file
View File

@ -0,0 +1,421 @@
Up to date documentation
========================
[Documentation](http://mongodb.github.com/node-mongodb-native/)
Install
=======
To install the most recent release from npm, run:
npm install mongodb
That may give you a warning telling you that bugs['web'] should be bugs['url'], it would be safe to ignore it (this has been fixed in the development version)
To install the latest from the repository, run::
npm install path/to/node-mongodb-native
Community
=========
Check out the google group [node-mongodb-native](http://groups.google.com/group/node-mongodb-native) for questions/answers from users of the driver.
Live Examples
============
<a href="https://runnable.com/node-mongodb-native" target="_blank"><img src="https://runnable.com/external/styles/assets/runnablebtn.png" style="width:67px;height:25px;"></a>
Introduction
============
This is a node.js driver for MongoDB. It's a port (or close to a port) of the library for ruby at http://github.com/mongodb/mongo-ruby-driver/.
A simple example of inserting a document.
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
var collection = db.collection('test_insert');
collection.insert({a:2}, function(err, docs) {
collection.count(function(err, count) {
console.log(format("count = %s", count));
});
// Locate all the entries using find
collection.find().toArray(function(err, results) {
console.dir(results);
// Let's close the db
db.close();
});
});
})
```
Data types
==========
To store and retrieve the non-JSON MongoDb primitives ([ObjectID](http://www.mongodb.org/display/DOCS/Object+IDs), Long, Binary, [Timestamp](http://www.mongodb.org/display/DOCS/Timestamp+data+type), [DBRef](http://www.mongodb.org/display/DOCS/Database+References#DatabaseReferences-DBRef), Code).
In particular, every document has a unique `_id` which can be almost any type, and by default a 12-byte ObjectID is created. ObjectIDs can be represented as 24-digit hexadecimal strings, but you must convert the string back into an ObjectID before you can use it in the database. For example:
```javascript
// Get the objectID type
var ObjectID = require('mongodb').ObjectID;
var idString = '4e4e1638c85e808431000003';
collection.findOne({_id: new ObjectID(idString)}, console.log) // ok
collection.findOne({_id: idString}, console.log) // wrong! callback gets undefined
```
Here are the constructors the non-Javascript BSON primitive types:
```javascript
// Fetch the library
var mongo = require('mongodb');
// Create new instances of BSON types
new mongo.Long(numberString)
new mongo.ObjectID(hexString)
new mongo.Timestamp() // the actual unique number is generated on insert.
new mongo.DBRef(collectionName, id, dbName)
new mongo.Binary(buffer) // takes a string or Buffer
new mongo.Code(code, [context])
new mongo.Symbol(string)
new mongo.MinKey()
new mongo.MaxKey()
new mongo.Double(number) // Force double storage
```
The C/C++ bson parser/serializer
--------------------------------
If you are running a version of this library has the C/C++ parser compiled, to enable the driver to use the C/C++ bson parser pass it the option native_parser:true like below
```javascript
// using native_parser:
MongoClient.connect('mongodb://127.0.0.1:27017/test'
, {db: {native_parser: true}}, function(err, db) {})
```
The C++ parser uses the js objects both for serialization and deserialization.
GitHub information
==================
The source code is available at http://github.com/mongodb/node-mongodb-native.
You can either clone the repository or download a tarball of the latest release.
Once you have the source you can test the driver by running
$ make test
in the main directory. You will need to have a mongo instance running on localhost for the integration tests to pass.
Examples
========
For examples look in the examples/ directory. You can execute the examples using node.
$ cd examples
$ node queries.js
GridStore
=========
The GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition.
For more information have a look at [Gridstore](https://github.com/mongodb/node-mongodb-native/blob/master/docs/gridfs.md)
Replicasets
===========
For more information about how to connect to a replicaset have a look at [Replicasets](https://github.com/mongodb/node-mongodb-native/blob/master/docs/replicaset.md)
Primary Key Factories
---------------------
Defining your own primary key factory allows you to generate your own series of id's
(this could f.ex be to use something like ISBN numbers). The generated the id needs to be a 12 byte long "string".
Simple example below
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
// Custom factory (need to provide a 12 byte array);
CustomPKFactory = function() {}
CustomPKFactory.prototype = new Object();
CustomPKFactory.createPk = function() {
return new ObjectID("aaaaaaaaaaaa");
}
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
db.dropDatabase(function(err, done) {
db.createCollection('test_custom_key', function(err, collection) {
collection.insert({'a':1}, function(err, docs) {
collection.find({'_id':new ObjectID("aaaaaaaaaaaa")}).toArray(function(err, items) {
console.dir(items);
// Let's close the db
db.close();
});
});
});
});
});
```
Documentation
=============
If this document doesn't answer your questions, see the source of
[Collection](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/collection.js)
or [Cursor](https://github.com/mongodb/node-mongodb-native/blob/master/lib/mongodb/cursor.js),
or the documentation at MongoDB for query and update formats.
Find
----
The find method is actually a factory method to create
Cursor objects. A Cursor lazily uses the connection the first time
you call `nextObject`, `each`, or `toArray`.
The basic operation on a cursor is the `nextObject` method
that fetches the next matching document from the database. The convenience
methods `each` and `toArray` call `nextObject` until the cursor is exhausted.
Signatures:
```javascript
var cursor = collection.find(query, [fields], options);
cursor.sort(fields).limit(n).skip(m).
cursor.nextObject(function(err, doc) {});
cursor.each(function(err, doc) {});
cursor.toArray(function(err, docs) {});
cursor.rewind() // reset the cursor to its initial state.
```
Useful chainable methods of cursor. These can optionally be options of `find` instead of method calls:
* `.limit(n).skip(m)` to control paging.
* `.sort(fields)` Order by the given fields. There are several equivalent syntaxes:
* `.sort({field1: -1, field2: 1})` descending by field1, then ascending by field2.
* `.sort([['field1', 'desc'], ['field2', 'asc']])` same as above
* `.sort([['field1', 'desc'], 'field2'])` same as above
* `.sort('field1')` ascending by field1
Other options of `find`:
* `fields` the fields to fetch (to avoid transferring the entire document)
* `tailable` if true, makes the cursor [tailable](http://www.mongodb.org/display/DOCS/Tailable+Cursors).
* `batchSize` The number of the subset of results to request the database
to return for every request. This should initially be greater than 1 otherwise
the database will automatically close the cursor. The batch size can be set to 1
with `batchSize(n, function(err){})` after performing the initial query to the database.
* `hint` See [Optimization: hint](http://www.mongodb.org/display/DOCS/Optimization#Optimization-Hint).
* `explain` turns this into an explain query. You can also call
`explain()` on any cursor to fetch the explanation.
* `snapshot` prevents documents that are updated while the query is active
from being returned multiple times. See more
[details about query snapshots](http://www.mongodb.org/display/DOCS/How+to+do+Snapshotted+Queries+in+the+Mongo+Database).
* `timeout` if false, asks MongoDb not to time out this cursor after an
inactivity period.
For information on how to create queries, see the
[MongoDB section on querying](http://www.mongodb.org/display/DOCS/Querying).
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
var collection = db
.collection('test')
.find({})
.limit(10)
.toArray(function(err, docs) {
console.dir(docs);
});
});
```
Insert
------
Signature:
```javascript
collection.insert(docs, options, [callback]);
```
where `docs` can be a single document or an array of documents.
Useful options:
* `safe:true` Should always set if you have a callback.
See also: [MongoDB docs for insert](http://www.mongodb.org/display/DOCS/Inserting).
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
db.collection('test').insert({hello: 'world'}, {w:1}, function(err, objects) {
if (err) console.warn(err.message);
if (err && err.message.indexOf('E11000 ') !== -1) {
// this _id was already inserted in the database
}
});
});
```
Note that there's no reason to pass a callback to the insert or update commands
unless you use the `safe:true` option. If you don't specify `safe:true`, then
your callback will be called immediately.
Update; update and insert (upsert)
----------------------------------
The update operation will update the first document that matches your query
(or all documents that match if you use `multi:true`).
If `safe:true`, `upsert` is not set, and no documents match, your callback will return 0 documents updated.
See the [MongoDB docs](http://www.mongodb.org/display/DOCS/Updating) for
the modifier (`$inc`, `$set`, `$push`, etc.) formats.
Signature:
```javascript
collection.update(criteria, objNew, options, [callback]);
```
Useful options:
* `safe:true` Should always set if you have a callback.
* `multi:true` If set, all matching documents are updated, not just the first.
* `upsert:true` Atomically inserts the document if no documents matched.
Example for `update`:
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
db.collection('test').update({hi: 'here'}, {$set: {hi: 'there'}}, {w:1}, function(err) {
if (err) console.warn(err.message);
else console.log('successfully updated');
});
});
```
Find and modify
---------------
`findAndModify` is like `update`, but it also gives the updated document to
your callback. But there are a few key differences between findAndModify and
update:
1. The signatures differ.
2. You can only findAndModify a single item, not multiple items.
Signature:
```javascript
collection.findAndModify(query, sort, update, options, callback)
```
The sort parameter is used to specify which object to operate on, if more than
one document matches. It takes the same format as the cursor sort (see
Connection.find above).
See the
[MongoDB docs for findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command)
for more details.
Useful options:
* `remove:true` set to a true to remove the object before returning
* `new:true` set to true if you want to return the modified object rather than the original. Ignored for remove.
* `upsert:true` Atomically inserts the document if no documents matched.
Example for `findAndModify`:
```javascript
var MongoClient = require('mongodb').MongoClient
, format = require('util').format;
MongoClient.connect('mongodb://127.0.0.1:27017/test', function(err, db) {
if(err) throw err;
db.collection('test').findAndModify({hello: 'world'}, [['_id','asc']], {$set: {hi: 'there'}}, {}, function(err, object) {
if (err) console.warn(err.message);
else console.dir(object); // undefined if no matching object exists.
});
});
```
Save
----
The `save` method is a shorthand for upsert if the document contains an
`_id`, or an insert if there is no `_id`.
Sponsors
========
Just as Felix Geisendörfer I'm also working on the driver for my own startup and this driver is a big project that also benefits other companies who are using MongoDB.
If your company could benefit from a even better-engineered node.js mongodb driver I would appreciate any type of sponsorship you may be able to provide. All the sponsors will get a lifetime display in this readme, priority support and help on problems and votes on the roadmap decisions for the driver. If you are interested contact me on [christkv AT g m a i l.com](mailto:christkv@gmail.com) for details.
And I'm very thankful for code contributions. If you are interested in working on features please contact me so we can discuss API design and testing.
Release Notes
=============
See HISTORY
Credits
=======
1. [10gen](http://github.com/mongodb/mongo-ruby-driver/)
2. [Google Closure Library](http://code.google.com/closure/library/)
3. [Jonas Raoni Soares Silva](http://jsfromhell.com/classes/binary-parser)
Contributors
============
Aaron Heckmann, Christoph Pojer, Pau Ramon Revilla, Nathan White, Emmerman, Seth LaForge, Boris Filipov, Stefan Schärmeli, Tedde Lundgren, renctan, Sergey Ukustov, Ciaran Jessup, kuno, srimonti, Erik Abele, Pratik Daga, Slobodan Utvic, Kristina Chodorow, Yonathan Randolph, Brian Noguchi, Sam Epstein, James Harrison Fisher, Vladimir Dronnikov, Ben Hockey, Henrik Johansson, Simon Weare, Alex Gorbatchev, Shimon Doodkin, Kyle Mueller, Eran Hammer-Lahav, Marcin Ciszak, François de Metz, Vinay Pulim, nstielau, Adam Wiggins, entrinzikyl, Jeremy Selier, Ian Millington, Public Keating, andrewjstone, Christopher Stott, Corey Jewett, brettkiefer, Rob Holland, Senmiao Liu, heroic, gitfy
License
=======
Copyright 2009 - 2012 Christian Amor Kvalheim.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

1
node_modules/mongoose/node_modules/mongodb/index.js generated vendored Executable file
View File

@ -0,0 +1 @@
module.exports = require('./lib/mongodb');

40
node_modules/mongoose/node_modules/mongodb/install.js generated vendored Normal file
View File

@ -0,0 +1,40 @@
var spawn = require('child_process').spawn,
exec = require('child_process').exec;
process.stdout.write("================================================================================\n");
process.stdout.write("= =\n");
process.stdout.write("= To install with C++ bson parser do <npm install mongodb --mongodb:native> =\n");
process.stdout.write("= =\n");
process.stdout.write("================================================================================\n");
// Check if we want to build the native code
var build_native = process.env['npm_package_config_native'] != null ? process.env['npm_package_config_native'] : 'false';
build_native = build_native == 'true' ? true : false;
// If we are building the native bson extension ensure we use gmake if available
if(build_native) {
// Check if we need to use gmake
exec('which gmake', function(err, stdout, stderr) {
// Set up spawn command
var make = null;
// No gmake build using make
if(err != null) {
make = spawn('make', ['total']);
} else {
make = spawn('gmake', ['total']);
}
// Execute spawn
make.stdout.on('data', function(data) {
process.stdout.write(data);
})
make.stderr.on('data', function(data) {
process.stdout.write(data);
})
make.on('exit', function(code) {
process.stdout.write('child process exited with code ' + code + "\n");
})
});
}

View File

@ -0,0 +1,339 @@
/*!
* Module dependencies.
*/
var Collection = require('./collection').Collection,
Cursor = require('./cursor').Cursor,
DbCommand = require('./commands/db_command').DbCommand,
utils = require('./utils');
/**
* Allows the user to access the admin functionality of MongoDB
*
* @class Represents the Admin methods of MongoDB.
* @param {Object} db Current db instance we wish to perform Admin operations on.
* @return {Function} Constructor for Admin type.
*/
function Admin(db) {
if(!(this instanceof Admin)) return new Admin(db);
this.db = db;
};
/**
* Retrieve the server information for the current
* instance of the db client
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from buildInfo or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.buildInfo = function(callback) {
this.serverInfo(callback);
}
/**
* Retrieve the server information for the current
* instance of the db client
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverInfo or null if an error occured.
* @return {null} Returns no result
* @api private
*/
Admin.prototype.serverInfo = function(callback) {
this.db.executeDbAdminCommand({buildinfo:1}, function(err, doc) {
if(err != null) return callback(err, null);
return callback(null, doc.documents[0]);
});
}
/**
* Retrieve this db's server status.
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from serverStatus or null if an error occured.
* @return {null}
* @api public
*/
Admin.prototype.serverStatus = function(callback) {
var self = this;
this.db.executeDbAdminCommand({serverStatus: 1}, function(err, doc) {
if(err == null && doc.documents[0].ok === 1) {
callback(null, doc.documents[0]);
} else {
if(err) return callback(err, false);
return callback(utils.toError(doc.documents[0]), false);
}
});
};
/**
* Retrieve the current profiling Level for MongoDB
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingLevel or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.profilingLevel = function(callback) {
var self = this;
this.db.executeDbAdminCommand({profile:-1}, function(err, doc) {
doc = doc.documents[0];
if(err == null && doc.ok === 1) {
var was = doc.was;
if(was == 0) return callback(null, "off");
if(was == 1) return callback(null, "slow_only");
if(was == 2) return callback(null, "all");
return callback(new Error("Error: illegal profiling level value " + was), null);
} else {
err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
}
});
};
/**
* Ping the MongoDB server and retrieve results
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from ping or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.ping = function(options, callback) {
// Unpack calls
var args = Array.prototype.slice.call(arguments, 0);
callback = args.pop();
this.db.executeDbAdminCommand({ping: 1}, callback);
}
/**
* Authenticate against MongoDB
*
* @param {String} username The user name for the authentication.
* @param {String} password The password for the authentication.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from authenticate or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.authenticate = function(username, password, callback) {
this.db.authenticate(username, password, {authdb: 'admin'}, function(err, doc) {
return callback(err, doc);
})
}
/**
* Logout current authenticated user
*
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from logout or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.logout = function(callback) {
this.db.logout({authdb: 'admin'}, function(err, doc) {
return callback(err, doc);
})
}
/**
* Add a user to the MongoDB server, if the user exists it will
* overwrite the current password
*
* Options
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
*
* @param {String} username The user name for the authentication.
* @param {String} password The password for the authentication.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from addUser or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.addUser = function(username, password, options, callback) {
var args = Array.prototype.slice.call(arguments, 2);
callback = args.pop();
options = args.length ? args.shift() : {};
options.dbName = 'admin';
// Add user
this.db.addUser(username, password, options, function(err, doc) {
return callback(err, doc);
})
}
/**
* Remove a user from the MongoDB server
*
* Options
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
*
* @param {String} username The user name for the authentication.
* @param {Object} [options] additional options during update.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from removeUser or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.removeUser = function(username, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
options.dbName = 'admin';
this.db.removeUser(username, options, function(err, doc) {
return callback(err, doc);
})
}
/**
* Set the current profiling level of MongoDB
*
* @param {String} level The new profiling level (off, slow_only, all)
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from setProfilingLevel or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.setProfilingLevel = function(level, callback) {
var self = this;
var command = {};
var profile = 0;
if(level == "off") {
profile = 0;
} else if(level == "slow_only") {
profile = 1;
} else if(level == "all") {
profile = 2;
} else {
return callback(new Error("Error: illegal profiling level value " + level));
}
// Set up the profile number
command['profile'] = profile;
this.db.executeDbAdminCommand(command, function(err, doc) {
doc = doc.documents[0];
if(err == null && doc.ok === 1)
return callback(null, level);
return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
});
};
/**
* Retrive the current profiling information for MongoDB
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from profilingInfo or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.profilingInfo = function(callback) {
try {
new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}, {}, {dbName: 'admin'}).toArray(function(err, items) {
return callback(err, items);
});
} catch (err) {
return callback(err, null);
}
};
/**
* Execute a db command against the Admin database
*
* @param {Object} command A command object `{ping:1}`.
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The command always return the whole result of the command as the second parameter.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.command = function(command, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
// Execute a command
this.db.executeDbAdminCommand(command, options, function(err, doc) {
// Ensure change before event loop executes
return callback != null ? callback(err, doc) : null;
});
}
/**
* Validate an existing collection
*
* @param {String} collectionName The name of the collection to validate.
* @param {Object} [options] Optional parameters to the command.
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from validateCollection or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.validateCollection = function(collectionName, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
var self = this;
var command = {validate: collectionName};
var keys = Object.keys(options);
// Decorate command with extra options
for(var i = 0; i < keys.length; i++) {
if(options.hasOwnProperty(keys[i])) {
command[keys[i]] = options[keys[i]];
}
}
this.db.executeDbCommand(command, function(err, doc) {
if(err != null) return callback(err, null);
doc = doc.documents[0];
if(doc.ok === 0)
return callback(new Error("Error with validate command"), null);
if(doc.result != null && doc.result.constructor != String)
return callback(new Error("Error with validation data"), null);
if(doc.result != null && doc.result.match(/exception|corrupt/) != null)
return callback(new Error("Error: invalid collection " + collectionName), null);
if(doc.valid != null && !doc.valid)
return callback(new Error("Error: invalid collection " + collectionName), null);
return callback(null, doc);
});
};
/**
* List the available databases
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from listDatabases or null if an error occured.
* @return {null} Returns no result
* @api public
*/
Admin.prototype.listDatabases = function(callback) {
// Execute the listAllDatabases command
this.db.executeDbAdminCommand({listDatabases:1}, {}, function(err, doc) {
if(err != null) return callback(err, null);
return callback(null, doc.documents[0]);
});
}
/**
* Get ReplicaSet status
*
* @param {Function} callback this will be called after executing this method. The first parameter will contain the Error object if an error occured, or null otherwise. While the second parameter will contain the results from replSetGetStatus or null if an error occured.
* @return {null}
* @api public
*/
Admin.prototype.replSetGetStatus = function(callback) {
var self = this;
this.db.executeDbAdminCommand({replSetGetStatus:1}, function(err, doc) {
if(err == null && doc.documents[0].ok === 1)
return callback(null, doc.documents[0]);
if(err) return callback(err, false);
return callback(utils.toError(doc.documents[0]), false);
});
};
/**
* @ignore
*/
exports.Admin = Admin;

View File

@ -0,0 +1,53 @@
var DbCommand = require('../commands/db_command').DbCommand
, utils = require('../utils');
var authenticate = function(db, username, password, authdb, options, callback) {
var numberOfConnections = 0;
var errorObject = null;
if(options['connection'] != null) {
//if a connection was explicitly passed on options, then we have only one...
numberOfConnections = 1;
} else {
// Get the amount of connections in the pool to ensure we have authenticated all comments
numberOfConnections = db.serverConfig.allRawConnections().length;
options['onAll'] = true;
}
// Execute all four
db._executeQueryCommand(DbCommand.createGetNonceCommand(db), options, function(err, result, connection) {
// Execute on all the connections
if(err == null) {
// Nonce used to make authentication request with md5 hash
var nonce = result.documents[0].nonce;
// Execute command
db._executeQueryCommand(DbCommand.createAuthenticationCommand(db, username, password, nonce, authdb), {connection:connection}, function(err, result) {
// Count down
numberOfConnections = numberOfConnections - 1;
// Ensure we save any error
if(err) {
errorObject = err;
} else if(result.documents[0].err != null || result.documents[0].errmsg != null){
errorObject = utils.toError(result.documents[0]);
}
// Work around the case where the number of connections are 0
if(numberOfConnections <= 0 && typeof callback == 'function') {
var internalCallback = callback;
callback = null;
if(errorObject == null && result.documents[0].ok == 1) {
// We authenticated correctly save the credentials
db.serverConfig.auth.add('MONGODB-CR', db.databaseName, username, password, authdb);
// Return callback
internalCallback(errorObject, true);
} else {
internalCallback(errorObject, false);
}
}
});
}
});
}
exports.authenticate = authenticate;

View File

@ -0,0 +1,149 @@
var DbCommand = require('../commands/db_command').DbCommand
, utils = require('../utils')
, format = require('util').format;
// Kerberos class
var Kerberos = null;
var MongoAuthProcess = null;
// Try to grab the Kerberos class
try {
Kerberos = require('kerberos').Kerberos
// Authentication process for Mongo
MongoAuthProcess = require('kerberos').processes.MongoAuthProcess
} catch(err) {}
var authenticate = function(db, username, password, authdb, options, callback) {
var numberOfConnections = 0;
var errorObject = null;
// We don't have the Kerberos library
if(Kerberos == null) return callback(new Error("Kerberos library is not installed"));
if(options['connection'] != null) {
//if a connection was explicitly passed on options, then we have only one...
numberOfConnections = 1;
} else {
// Get the amount of connections in the pool to ensure we have authenticated all comments
numberOfConnections = db.serverConfig.allRawConnections().length;
options['onAll'] = true;
}
// Grab all the connections
var connections = options['connection'] != null ? [options['connection']] : db.serverConfig.allRawConnections();
var gssapiServiceName = options['gssapiServiceName'] || 'mongodb';
var error = null;
// Authenticate all connections
for(var i = 0; i < numberOfConnections; i++) {
// Start Auth process for a connection
GSSAPIInitialize(db, username, password, authdb, gssapiServiceName, connections[i], function(err, result) {
// Adjust number of connections left to connect
numberOfConnections = numberOfConnections - 1;
// If we have an error save it
if(err) error = err;
// We are done
if(numberOfConnections == 0) {
if(err) return callback(error, false);
// We authenticated correctly save the credentials
db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb, gssapiServiceName);
// Return valid callback
return callback(null, true);
}
});
}
}
//
// Initialize step
var GSSAPIInitialize = function(db, username, password, authdb, gssapiServiceName, connection, callback) {
// Create authenticator
var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port, gssapiServiceName);
// Perform initialization
mongo_auth_process.init(username, password, function(err, context) {
if(err) return callback(err, false);
// Perform the first step
mongo_auth_process.transition('', function(err, payload) {
if(err) return callback(err, false);
// Call the next db step
MongoDBGSSAPIFirstStep(mongo_auth_process, payload, db, username, password, authdb, connection, callback);
});
});
}
//
// Perform first step against mongodb
var MongoDBGSSAPIFirstStep = function(mongo_auth_process, payload, db, username, password, authdb, connection, callback) {
// Build the sasl start command
var command = {
saslStart: 1
, mechanism: 'GSSAPI'
, payload: payload
, autoAuthorize: 1
};
// Execute first sasl step
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err, false);
// Get the payload
doc = doc.documents[0];
var db_payload = doc.payload;
mongo_auth_process.transition(doc.payload, function(err, payload) {
if(err) return callback(err, false);
// MongoDB API Second Step
MongoDBGSSAPISecondStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback);
});
});
}
//
// Perform first step against mongodb
var MongoDBGSSAPISecondStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) {
// Build Authentication command to send to MongoDB
var command = {
saslContinue: 1
, conversationId: doc.conversationId
, payload: payload
};
// Execute the command
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err, false);
// Get the result document
doc = doc.documents[0];
// Call next transition for kerberos
mongo_auth_process.transition(doc.payload, function(err, payload) {
if(err) return callback(err, false);
// Call the last and third step
MongoDBGSSAPIThirdStep(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback);
});
});
}
var MongoDBGSSAPIThirdStep = function(mongo_auth_process, payload, doc, db, username, password, authdb, connection, callback) {
// Build final command
var command = {
saslContinue: 1
, conversationId: doc.conversationId
, payload: payload
};
// Let's finish the auth process against mongodb
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err, false);
mongo_auth_process.transition(null, function(err, payload) {
if(err) return callback(err, false);
callback(null, true);
});
});
}
exports.authenticate = authenticate;

View File

@ -0,0 +1,66 @@
var DbCommand = require('../commands/db_command').DbCommand
, utils = require('../utils')
, Binary = require('bson').Binary
, format = require('util').format;
var authenticate = function(db, username, password, options, callback) {
var numberOfConnections = 0;
var errorObject = null;
if(options['connection'] != null) {
//if a connection was explicitly passed on options, then we have only one...
numberOfConnections = 1;
} else {
// Get the amount of connections in the pool to ensure we have authenticated all comments
numberOfConnections = db.serverConfig.allRawConnections().length;
options['onAll'] = true;
}
// Create payload
var payload = new Binary(format("\x00%s\x00%s", username, password));
// Let's start the sasl process
var command = {
saslStart: 1
, mechanism: 'PLAIN'
, payload: payload
, autoAuthorize: 1
};
// Grab all the connections
var connections = options['connection'] != null ? [options['connection']] : db.serverConfig.allRawConnections();
// Authenticate all connections
for(var i = 0; i < numberOfConnections; i++) {
var connection = connections[i];
// Execute first sasl step
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, result) {
// Count down
numberOfConnections = numberOfConnections - 1;
// Ensure we save any error
if(err) {
errorObject = err;
} else if(result.documents[0].err != null || result.documents[0].errmsg != null){
errorObject = utils.toError(result.documents[0]);
}
// Work around the case where the number of connections are 0
if(numberOfConnections <= 0 && typeof callback == 'function') {
var internalCallback = callback;
callback = null;
if(errorObject == null && result.documents[0].ok == 1) {
// We authenticated correctly save the credentials
db.serverConfig.auth.add('PLAIN', db.databaseName, username, password);
// Return callback
internalCallback(errorObject, true);
} else {
internalCallback(errorObject, false);
}
}
});
}
}
exports.authenticate = authenticate;

View File

@ -0,0 +1,135 @@
var DbCommand = require('../commands/db_command').DbCommand
, utils = require('../utils')
, format = require('util').format;
// Kerberos class
var Kerberos = null;
var MongoAuthProcess = null;
// Try to grab the Kerberos class
try {
Kerberos = require('kerberos').Kerberos
// Authentication process for Mongo
MongoAuthProcess = require('kerberos').processes.MongoAuthProcess
} catch(err) {}
var authenticate = function(db, username, password, authdb, options, callback) {
var numberOfConnections = 0;
var errorObject = null;
// We don't have the Kerberos library
if(Kerberos == null) return callback(new Error("Kerberos library is not installed"));
if(options['connection'] != null) {
//if a connection was explicitly passed on options, then we have only one...
numberOfConnections = 1;
} else {
// Get the amount of connections in the pool to ensure we have authenticated all comments
numberOfConnections = db.serverConfig.allRawConnections().length;
options['onAll'] = true;
}
var connection = db.serverConfig.allRawConnections()[0];
var gssapiServiceName = options['gssapiServiceName'] || 'mongodb';
// Grab all the connections
var connections = db.serverConfig.allRawConnections();
var error = null;
// Authenticate all connections
for(var i = 0; i < numberOfConnections; i++) {
// Start Auth process for a connection
SSIPAuthenticate(db, username, password, authdb, gssapiServiceName, connections[i], function(err, result) {
// Adjust number of connections left to connect
numberOfConnections = numberOfConnections - 1;
// If we have an error save it
if(err) error = err;
// We are done
if(numberOfConnections == 0) {
if(err) return callback(err, false);
// We authenticated correctly save the credentials
db.serverConfig.auth.add('GSSAPI', db.databaseName, username, password, authdb, gssapiServiceName);
// Return valid callback
return callback(null, true);
}
});
}
}
var SSIPAuthenticate = function(db, username, password, authdb, service_name, connection, callback) {
// --------------------------------------------------------------
// Async Version
// --------------------------------------------------------------
var command = {
saslStart: 1
, mechanism: 'GSSAPI'
, payload: ''
, autoAuthorize: 1
};
// Create authenticator
var mongo_auth_process = new MongoAuthProcess(connection.socketOptions.host, connection.socketOptions.port, service_name);
// Execute first sasl step
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err);
doc = doc.documents[0];
mongo_auth_process.init(username, password, function(err) {
if(err) return callback(err);
mongo_auth_process.transition(doc.payload, function(err, payload) {
if(err) return callback(err);
// Perform the next step against mongod
var command = {
saslContinue: 1
, conversationId: doc.conversationId
, payload: payload
};
// Execute the command
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err);
doc = doc.documents[0];
mongo_auth_process.transition(doc.payload, function(err, payload) {
if(err) return callback(err);
// Perform the next step against mongod
var command = {
saslContinue: 1
, conversationId: doc.conversationId
, payload: payload
};
// Execute the command
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err);
doc = doc.documents[0];
mongo_auth_process.transition(doc.payload, function(err, payload) {
// Perform the next step against mongod
var command = {
saslContinue: 1
, conversationId: doc.conversationId
, payload: payload
};
// Execute the command
db._executeQueryCommand(DbCommand.createDbCommand(db, command, {}, '$external'), {connection:connection}, function(err, doc) {
if(err) return callback(err);
doc = doc.documents[0];
if(doc.done) return callback(null, true);
callback(new Error("Authentication failed"), false);
});
});
});
});
});
});
});
});
}
exports.authenticate = authenticate;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
/**
Base object used for common functionality
**/
var BaseCommand = exports.BaseCommand = function BaseCommand() {
};
var id = 1;
BaseCommand.prototype.getRequestId = function getRequestId() {
if (!this.requestId) this.requestId = id++;
return this.requestId;
};
BaseCommand.prototype.setMongosReadPreference = function setMongosReadPreference(readPreference, tags) {}
BaseCommand.prototype.updateRequestId = function() {
this.requestId = id++;
return this.requestId;
};
// OpCodes
BaseCommand.OP_REPLY = 1;
BaseCommand.OP_MSG = 1000;
BaseCommand.OP_UPDATE = 2001;
BaseCommand.OP_INSERT = 2002;
BaseCommand.OP_GET_BY_OID = 2003;
BaseCommand.OP_QUERY = 2004;
BaseCommand.OP_GET_MORE = 2005;
BaseCommand.OP_DELETE = 2006;
BaseCommand.OP_KILL_CURSORS = 2007;

View File

@ -0,0 +1,245 @@
var QueryCommand = require('./query_command').QueryCommand,
InsertCommand = require('./insert_command').InsertCommand,
inherits = require('util').inherits,
utils = require('../utils'),
crypto = require('crypto');
/**
Db Command
**/
var DbCommand = exports.DbCommand = function(dbInstance, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
QueryCommand.call(this);
this.collectionName = collectionName;
this.queryOptions = queryOptions;
this.numberToSkip = numberToSkip;
this.numberToReturn = numberToReturn;
this.query = query;
this.returnFieldSelector = returnFieldSelector;
this.db = dbInstance;
if(this.db && this.db.slaveOk) {
this.queryOptions |= QueryCommand.OPTS_SLAVE;
}
// Make sure we don't get a null exception
options = options == null ? {} : options;
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(DbCommand, QueryCommand);
// Constants
DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes";
DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile";
DbCommand.SYSTEM_USER_COLLECTION = "system.users";
DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd";
DbCommand.SYSTEM_JS_COLLECTION = "system.js";
// New commands
DbCommand.NcreateIsMasterCommand = function(db, databaseName) {
return new DbCommand(db, databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
};
// Provide constructors for different db commands
DbCommand.createIsMasterCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
};
DbCommand.createCollectionInfoCommand = function(db, selector) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null);
};
DbCommand.createGetNonceCommand = function(db, options) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null);
};
DbCommand.createAuthenticationCommand = function(db, username, password, nonce, authdb) {
// Use node md5 generator
var md5 = crypto.createHash('md5');
// Generate keys used for authentication
md5.update(username + ":mongo:" + password);
var hash_password = md5.digest('hex');
// Final key
md5 = crypto.createHash('md5');
md5.update(nonce + username + hash_password);
var key = md5.digest('hex');
// Creat selector
var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key};
// Create db command
return new DbCommand(db, authdb + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null);
};
DbCommand.createLogoutCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null);
};
DbCommand.createCreateCollectionCommand = function(db, collectionName, options) {
var selector = {'create':collectionName};
// Modify the options to ensure correct behaviour
for(var name in options) {
if(options[name] != null && options[name].constructor != Function) selector[name] = options[name];
}
// Execute the command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null);
};
DbCommand.createDropCollectionCommand = function(db, collectionName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null);
};
DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName, options) {
var renameCollection = db.databaseName + "." + fromCollectionName;
var toCollection = db.databaseName + "." + toCollectionName;
var dropTarget = options && options.dropTarget ? options.dropTarget : false;
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection, 'dropTarget':dropTarget}, null);
};
DbCommand.createGetLastErrorCommand = function(options, db) {
if (typeof db === 'undefined') {
db = options;
options = {};
}
// Final command
var command = {'getlasterror':1};
// If we have an options Object let's merge in the fields (fsync/wtimeout/w)
if('object' === typeof options) {
for(var name in options) {
command[name] = options[name]
}
}
// Special case for w == 1, remove the w
if(1 == command.w) {
delete command.w;
}
// Execute command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null);
};
DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand;
DbCommand.createGetPreviousErrorsCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null);
};
DbCommand.createResetErrorHistoryCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null);
};
DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) {
var fieldHash = {};
var indexes = [];
var keys;
// Get all the fields accordingly
if('string' == typeof fieldOrSpec) {
// 'type'
indexes.push(fieldOrSpec + '_' + 1);
fieldHash[fieldOrSpec] = 1;
} else if(utils.isArray(fieldOrSpec)) {
fieldOrSpec.forEach(function(f) {
if('string' == typeof f) {
// [{location:'2d'}, 'type']
indexes.push(f + '_' + 1);
fieldHash[f] = 1;
} else if(utils.isArray(f)) {
// [['location', '2d'],['type', 1]]
indexes.push(f[0] + '_' + (f[1] || 1));
fieldHash[f[0]] = f[1] || 1;
} else if(utils.isObject(f)) {
// [{location:'2d'}, {type:1}]
keys = Object.keys(f);
keys.forEach(function(k) {
indexes.push(k + '_' + f[k]);
fieldHash[k] = f[k];
});
} else {
// undefined (ignore)
}
});
} else if(utils.isObject(fieldOrSpec)) {
// {location:'2d', type:1}
keys = Object.keys(fieldOrSpec);
keys.forEach(function(key) {
indexes.push(key + '_' + fieldOrSpec[key]);
fieldHash[key] = fieldOrSpec[key];
});
}
// Generate the index name
var indexName = typeof options.name == 'string'
? options.name
: indexes.join("_");
var selector = {
'ns': db.databaseName + "." + collectionName,
'key': fieldHash,
'name': indexName
}
// Ensure we have a correct finalUnique
var finalUnique = options == null || 'object' === typeof options
? false
: options;
// Set up options
options = options == null || typeof options == 'boolean'
? {}
: options;
// Add all the options
var keys = Object.keys(options);
for(var i = 0; i < keys.length; i++) {
selector[keys[i]] = options[keys[i]];
}
if(selector['unique'] == null)
selector['unique'] = finalUnique;
var name = db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION;
var cmd = new InsertCommand(db, name, false);
return cmd.add(selector);
};
DbCommand.logoutCommand = function(db, command_hash, options) {
var dbName = options != null && options['authdb'] != null ? options['authdb'] : db.databaseName;
return new DbCommand(db, dbName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
}
DbCommand.createDropIndexCommand = function(db, collectionName, indexName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null);
};
DbCommand.createReIndexCommand = function(db, collectionName) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reIndex':collectionName}, null);
};
DbCommand.createDropDatabaseCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null);
};
DbCommand.createDbCommand = function(db, command_hash, options, auth_db) {
var db_name = (auth_db ? auth_db : db.databaseName) + "." + DbCommand.SYSTEM_COMMAND_COLLECTION;
return new DbCommand(db, db_name, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null, options);
};
DbCommand.createAdminDbCommand = function(db, command_hash) {
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
};
DbCommand.createAdminDbCommandSlaveOk = function(db, command_hash) {
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null);
};
DbCommand.createDbSlaveOkCommand = function(db, command_hash, options) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null, options);
};

View File

@ -0,0 +1,114 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector, flags) {
BaseCommand.call(this);
// Validate correctness off the selector
var object = selector;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("delete raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.flags = flags;
this.collectionName = collectionName;
this.selector = selector;
this.db = db;
};
inherits(DeleteCommand, BaseCommand);
DeleteCommand.OP_DELETE = 2006;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
int32 ZERO; // 0 - reserved for future use
mongo.BSON selector; // query object. See below for details.
}
*/
DeleteCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.selector, false, true) + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff;
_command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff;
_command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff;
_command[_index] = DeleteCommand.OP_DELETE & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the flags
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(this.selector)) {
documentLength = this.selector.length;
// Copy the data into the current buffer
this.selector.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
return _command;
};

View File

@ -0,0 +1,83 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits,
binaryutils = require('../utils');
/**
Get More Document Command
**/
var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) {
BaseCommand.call(this);
this.collectionName = collectionName;
this.numberToReturn = numberToReturn;
this.cursorId = cursorId;
this.db = db;
};
inherits(GetMoreCommand, BaseCommand);
GetMoreCommand.OP_GET_MORE = 2005;
GetMoreCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index++] = totalLengthOfCommand & 0xff;
_command[_index++] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index++] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index++] = (totalLengthOfCommand >> 24) & 0xff;
// Write the request ID
_command[_index++] = this.requestId & 0xff;
_command[_index++] = (this.requestId >> 8) & 0xff;
_command[_index++] = (this.requestId >> 16) & 0xff;
_command[_index++] = (this.requestId >> 24) & 0xff;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index++] = GetMoreCommand.OP_GET_MORE & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff;
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Number of documents to return
_command[_index++] = this.numberToReturn & 0xff;
_command[_index++] = (this.numberToReturn >> 8) & 0xff;
_command[_index++] = (this.numberToReturn >> 16) & 0xff;
_command[_index++] = (this.numberToReturn >> 24) & 0xff;
// Encode the cursor id
var low_bits = this.cursorId.getLowBits();
// Encode low bits
_command[_index++] = low_bits & 0xff;
_command[_index++] = (low_bits >> 8) & 0xff;
_command[_index++] = (low_bits >> 16) & 0xff;
_command[_index++] = (low_bits >> 24) & 0xff;
var high_bits = this.cursorId.getHighBits();
// Encode high bits
_command[_index++] = high_bits & 0xff;
_command[_index++] = (high_bits >> 8) & 0xff;
_command[_index++] = (high_bits >> 16) & 0xff;
_command[_index++] = (high_bits >> 24) & 0xff;
// Return command
return _command;
};

View File

@ -0,0 +1,147 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys, options) {
BaseCommand.call(this);
this.collectionName = collectionName;
this.documents = [];
this.checkKeys = checkKeys == null ? true : checkKeys;
this.db = db;
this.flags = 0;
this.serializeFunctions = false;
// Ensure valid options hash
options = options == null ? {} : options;
// Check if we have keepGoing set -> set flag if it's the case
if(options['keepGoing'] != null && options['keepGoing']) {
// This will finish inserting all non-index violating documents even if it returns an error
this.flags = 1;
}
// Check if we have keepGoing set -> set flag if it's the case
if(options['continueOnError'] != null && options['continueOnError']) {
// This will finish inserting all non-index violating documents even if it returns an error
this.flags = 1;
}
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(InsertCommand, BaseCommand);
// OpCodes
InsertCommand.OP_INSERT = 2002;
InsertCommand.prototype.add = function(document) {
if(Buffer.isBuffer(document)) {
var object_size = document[0] | document[1] << 8 | document[2] << 16 | document[3] << 24;
if(object_size != document.length) {
var error = new Error("insert raw message size does not match message header size [" + document.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.documents.push(document);
return this;
};
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
BSON[] documents; // one or more documents to insert into the collection
}
*/
InsertCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4);
// var docLength = 0
for(var i = 0; i < this.documents.length; i++) {
if(Buffer.isBuffer(this.documents[i])) {
totalLengthOfCommand += this.documents[i].length;
} else {
// Calculate size of document
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.documents[i], this.serializeFunctions, true);
}
}
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff;
_command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff;
_command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff;
_command[_index] = InsertCommand.OP_INSERT & 0xff;
// Adjust index
_index = _index + 4;
// Write flags if any
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write all the bson documents to the buffer at the index offset
for(var i = 0; i < this.documents.length; i++) {
// Document binary length
var documentLength = 0
var object = this.documents[i];
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
// Serialize the document straight to the buffer
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
return _command;
};

View File

@ -0,0 +1,98 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits,
binaryutils = require('../utils');
/**
Insert Document Command
**/
var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) {
BaseCommand.call(this);
this.cursorIds = cursorIds;
this.db = db;
};
inherits(KillCursorCommand, BaseCommand);
KillCursorCommand.OP_KILL_CURSORS = 2007;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
int32 numberOfCursorIDs; // number of cursorIDs in message
int64[] cursorIDs; // array of cursorIDs to close
}
*/
KillCursorCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff;
_command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff;
_command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff;
_command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Number of cursors to kill
var numberOfCursors = this.cursorIds.length;
_command[_index + 3] = (numberOfCursors >> 24) & 0xff;
_command[_index + 2] = (numberOfCursors >> 16) & 0xff;
_command[_index + 1] = (numberOfCursors >> 8) & 0xff;
_command[_index] = numberOfCursors & 0xff;
// Adjust index
_index = _index + 4;
// Encode all the cursors
for(var i = 0; i < this.cursorIds.length; i++) {
// Encode the cursor id
var low_bits = this.cursorIds[i].getLowBits();
// Encode low bits
_command[_index + 3] = (low_bits >> 24) & 0xff;
_command[_index + 2] = (low_bits >> 16) & 0xff;
_command[_index + 1] = (low_bits >> 8) & 0xff;
_command[_index] = low_bits & 0xff;
// Adjust index
_index = _index + 4;
var high_bits = this.cursorIds[i].getHighBits();
// Encode high bits
_command[_index + 3] = (high_bits >> 24) & 0xff;
_command[_index + 2] = (high_bits >> 16) & 0xff;
_command[_index + 1] = (high_bits >> 8) & 0xff;
_command[_index] = high_bits & 0xff;
// Adjust index
_index = _index + 4;
}
return _command;
};

View File

@ -0,0 +1,266 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Insert Document Command
**/
var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
BaseCommand.call(this);
// Validate correctness off the selector
var object = query,
object_size;
if(Buffer.isBuffer(object)) {
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
object = returnFieldSelector;
if(Buffer.isBuffer(object)) {
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
// Make sure we don't get a null exception
options = options == null ? {} : options;
// Set up options
this.collectionName = collectionName;
this.queryOptions = queryOptions;
this.numberToSkip = numberToSkip;
this.numberToReturn = numberToReturn;
// Ensure we have no null query
query = query == null ? {} : query;
// Wrap query in the $query parameter so we can add read preferences for mongos
this.query = query;
this.returnFieldSelector = returnFieldSelector;
this.db = db;
// Force the slave ok flag to be set if we are not using primary read preference
if(this.db && this.db.slaveOk) {
this.queryOptions |= QueryCommand.OPTS_SLAVE;
}
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(QueryCommand, BaseCommand);
QueryCommand.OP_QUERY = 2004;
/*
* Adds the read prefrence to the current command
*/
QueryCommand.prototype.setMongosReadPreference = function(readPreference, tags) {
// If we have readPreference set to true set to secondary prefered
if(readPreference == true) {
readPreference = 'secondaryPreferred';
} else if(readPreference == 'false') {
readPreference = 'primary';
}
// Force the slave ok flag to be set if we are not using primary read preference
if(readPreference != false && readPreference != 'primary') {
this.queryOptions |= QueryCommand.OPTS_SLAVE;
}
// Backward compatibility, ensure $query only set on read preference so 1.8.X works
if((readPreference != null || tags != null) && this.query['$query'] == null) {
this.query = {'$query': this.query};
}
// If we have no readPreference set and no tags, check if the slaveOk bit is set
if(readPreference == null && tags == null) {
// If we have a slaveOk bit set the read preference for MongoS
if(this.queryOptions & QueryCommand.OPTS_SLAVE) {
this.query['$readPreference'] = {mode: 'secondary'}
} else {
this.query['$readPreference'] = {mode: 'primary'}
}
}
// Build read preference object
if(typeof readPreference == 'object' && readPreference['_type'] == 'ReadPreference') {
this.query['$readPreference'] = readPreference.toObject();
} else if(readPreference != null) {
// Add the read preference
this.query['$readPreference'] = {mode: readPreference};
// If we have tags let's add them
if(tags != null) {
this.query['$readPreference']['tags'] = tags;
}
}
}
/*
struct {
MsgHeader header; // standard message header
int32 opts; // query options. See below for details.
cstring fullCollectionName; // "dbname.collectionname"
int32 numberToSkip; // number of documents to skip when returning results
int32 numberToReturn; // number of documents to return in the first OP_REPLY
BSON query ; // query object. See below for details.
[ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details.
}
*/
QueryCommand.prototype.toBinary = function() {
// Total length of the command
var totalLengthOfCommand = 0;
// Calculate total length of the document
if(Buffer.isBuffer(this.query)) {
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.query.length + (4 * 4);
} else {
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson.calculateObjectSize(this.query, this.serializeFunctions, true) + (4 * 4);
}
// Calculate extra fields size
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
if(Object.keys(this.returnFieldSelector).length > 0) {
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.returnFieldSelector, this.serializeFunctions, true);
}
} else if(Buffer.isBuffer(this.returnFieldSelector)) {
totalLengthOfCommand += this.returnFieldSelector.length;
}
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff;
_command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff;
_command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff;
_command[_index] = QueryCommand.OP_QUERY & 0xff;
// Adjust index
_index = _index + 4;
// Write the query options
_command[_index + 3] = (this.queryOptions >> 24) & 0xff;
_command[_index + 2] = (this.queryOptions >> 16) & 0xff;
_command[_index + 1] = (this.queryOptions >> 8) & 0xff;
_command[_index] = this.queryOptions & 0xff;
// Adjust index
_index = _index + 4;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the number of documents to skip
_command[_index + 3] = (this.numberToSkip >> 24) & 0xff;
_command[_index + 2] = (this.numberToSkip >> 16) & 0xff;
_command[_index + 1] = (this.numberToSkip >> 8) & 0xff;
_command[_index] = this.numberToSkip & 0xff;
// Adjust index
_index = _index + 4;
// Write the number of documents to return
_command[_index + 3] = (this.numberToReturn >> 24) & 0xff;
_command[_index + 2] = (this.numberToReturn >> 16) & 0xff;
_command[_index + 1] = (this.numberToReturn >> 8) & 0xff;
_command[_index] = this.numberToReturn & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
var object = this.query;
// Serialize the selector
if(Buffer.isBuffer(object)) {
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
// Serialize the document straight to the buffer
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
// Push field selector if available
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
if(Object.keys(this.returnFieldSelector).length > 0) {
var documentLength = this.db.bson.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
} if(this.returnFieldSelector != null && Buffer.isBuffer(this.returnFieldSelector)) {
// Document binary length
var documentLength = 0
var object = this.returnFieldSelector;
// Serialize the selector
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
}
// Return finished command
return _command;
};
// Constants
QueryCommand.OPTS_NONE = 0;
QueryCommand.OPTS_TAILABLE_CURSOR = 2;
QueryCommand.OPTS_SLAVE = 4;
QueryCommand.OPTS_OPLOG_REPLY = 8;
QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
QueryCommand.OPTS_AWAIT_DATA = 32;
QueryCommand.OPTS_EXHAUST = 64;
QueryCommand.OPTS_PARTIAL = 128;

View File

@ -0,0 +1,174 @@
var BaseCommand = require('./base_command').BaseCommand,
inherits = require('util').inherits;
/**
Update Document Command
**/
var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) {
BaseCommand.call(this);
var object = spec;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("update spec raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
var object = document;
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) {
var error = new Error("update document raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
error.name = 'MongoError';
throw error;
}
}
this.collectionName = collectionName;
this.spec = spec;
this.document = document;
this.db = db;
this.serializeFunctions = false;
// Generate correct flags
var db_upsert = 0;
var db_multi_update = 0;
db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert;
db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update;
// Flags
this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2);
// Let us defined on a command basis if we want functions to be serialized or not
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
this.serializeFunctions = true;
}
};
inherits(UpdateCommand, BaseCommand);
UpdateCommand.OP_UPDATE = 2001;
/*
struct {
MsgHeader header; // standard message header
int32 ZERO; // 0 - reserved for future use
cstring fullCollectionName; // "dbname.collectionname"
int32 flags; // bit vector. see below
BSON spec; // the query to select the document
BSON document; // the document data to update with or insert
}
*/
UpdateCommand.prototype.toBinary = function() {
// Calculate total length of the document
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.spec, false, true) +
this.db.bson.calculateObjectSize(this.document, this.serializeFunctions, true) + (4 * 4);
// Let's build the single pass buffer command
var _index = 0;
var _command = new Buffer(totalLengthOfCommand);
// Write the header information to the buffer
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
_command[_index] = totalLengthOfCommand & 0xff;
// Adjust index
_index = _index + 4;
// Write the request ID
_command[_index + 3] = (this.requestId >> 24) & 0xff;
_command[_index + 2] = (this.requestId >> 16) & 0xff;
_command[_index + 1] = (this.requestId >> 8) & 0xff;
_command[_index] = this.requestId & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the op_code for the command
_command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff;
_command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff;
_command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff;
_command[_index] = UpdateCommand.OP_UPDATE & 0xff;
// Adjust index
_index = _index + 4;
// Write zero
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
_command[_index++] = 0;
// Write the collection name to the command
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
_command[_index - 1] = 0;
// Write the update flags
_command[_index + 3] = (this.flags >> 24) & 0xff;
_command[_index + 2] = (this.flags >> 16) & 0xff;
_command[_index + 1] = (this.flags >> 8) & 0xff;
_command[_index] = this.flags & 0xff;
// Adjust index
_index = _index + 4;
// Document binary length
var documentLength = 0
var object = this.spec;
// Serialize the selector
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, false) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
// Document binary length
var documentLength = 0
var object = this.document;
// Serialize the document
// If we are passing a raw buffer, do minimal validation
if(Buffer.isBuffer(object)) {
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
documentLength = object.length;
// Copy the data into the current buffer
object.copy(_command, _index);
} else {
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
}
// Write the length to the document
_command[_index + 3] = (documentLength >> 24) & 0xff;
_command[_index + 2] = (documentLength >> 16) & 0xff;
_command[_index + 1] = (documentLength >> 8) & 0xff;
_command[_index] = documentLength & 0xff;
// Update index in buffer
_index = _index + documentLength;
// Add terminating 0 for the object
_command[_index - 1] = 0;
return _command;
};
// Constants
UpdateCommand.DB_UPSERT = 0;
UpdateCommand.DB_MULTI_UPDATE = 1;

View File

@ -0,0 +1,466 @@
var EventEmitter = require('events').EventEmitter
, inherits = require('util').inherits
, mongodb_cr_authenticate = require('../auth/mongodb_cr.js').authenticate
, mongodb_gssapi_authenticate = require('../auth/mongodb_gssapi.js').authenticate
, mongodb_sspi_authenticate = require('../auth/mongodb_sspi.js').authenticate;
var id = 0;
/**
* Internal class for callback storage
* @ignore
*/
var CallbackStore = function() {
// Make class an event emitter
EventEmitter.call(this);
// Add a info about call variable
this._notReplied = {};
this.id = id++;
}
/**
* @ignore
*/
inherits(CallbackStore, EventEmitter);
CallbackStore.prototype.notRepliedToIds = function() {
return Object.keys(this._notReplied);
}
CallbackStore.prototype.callbackInfo = function(id) {
return this._notReplied[id];
}
/**
* Internal class for holding non-executed commands
* @ignore
*/
var NonExecutedOperationStore = function(config) {
this.config = config;
this.commands = {
read: []
, write_reads: []
, write: []
};
}
NonExecutedOperationStore.prototype.write = function(op) {
this.commands.write.push(op);
}
NonExecutedOperationStore.prototype.read_from_writer = function(op) {
this.commands.write_reads.push(op);
}
NonExecutedOperationStore.prototype.read = function(op) {
this.commands.read.push(op);
}
NonExecutedOperationStore.prototype.execute_queries = function(executeInsertCommand) {
var connection = this.config.checkoutReader();
if(connection == null || connection instanceof Error) return;
// Write out all the queries
while(this.commands.read.length > 0) {
// Get the next command
var command = this.commands.read.shift();
// command['options'].connection = this.config.checkoutReader();
command.options.connection = connection;
// Execute the next command
command.executeQueryCommand(command.db, command.db_command, command.options, command.callback);
}
}
NonExecutedOperationStore.prototype.execute_writes = function() {
var connection = this.config.checkoutWriter();
if(connection == null || connection instanceof Error) return;
// Write out all the queries to the primary
while(this.commands.write_reads.length > 0) {
// Get the next command
var command = this.commands.write_reads.shift();
command.options.connection = connection;
// Execute the next command
command.executeQueryCommand(command.db, command.db_command, command.options, command.callback);
}
// Execute all write operations
while(this.commands.write.length > 0) {
// Get the next command
var command = this.commands.write.shift();
// Set the connection
command.options.connection = connection;
// Execute the next command
command.executeInsertCommand(command.db, command.db_command, command.options, command.callback);
}
}
/**
* Internal class for authentication storage
* @ignore
*/
var AuthStore = function() {
this._auths = [];
}
AuthStore.prototype.add = function(authMechanism, dbName, username, password, authdbName, gssapiServiceName) {
// Check for duplicates
if(!this.contains(dbName)) {
// Base config
var config = {
'username':username
, 'password':password
, 'db': dbName
, 'authMechanism': authMechanism
, 'gssapiServiceName': gssapiServiceName
};
// Add auth source if passed in
if(typeof authdbName == 'string') {
config['authdb'] = authdbName;
}
// Push the config
this._auths.push(config);
}
}
AuthStore.prototype.contains = function(dbName) {
for(var i = 0; i < this._auths.length; i++) {
if(this._auths[i].db == dbName) return true;
}
return false;
}
AuthStore.prototype.remove = function(dbName) {
var newAuths = [];
// Filter out all the login details
for(var i = 0; i < this._auths.length; i++) {
if(this._auths[i].db != dbName) newAuths.push(this._auths[i]);
}
// Set the filtered list
this._auths = newAuths;
}
AuthStore.prototype.get = function(index) {
return this._auths[index];
}
AuthStore.prototype.length = function() {
return this._auths.length;
}
AuthStore.prototype.toArray = function() {
return this._auths.slice(0);
}
/**
* Internal class for storing db references
* @ignore
*/
var DbStore = function() {
this._dbs = [];
}
DbStore.prototype.add = function(db) {
// this._dbs.push(db);
var found = false;
// Only add if it does not exist already
for(var i = 0; i < this._dbs.length; i++) {
if(db.databaseName == this._dbs[i].databaseName) found = true;
}
if(!found) this._dbs.push(db);
}
DbStore.prototype.reset = function() {
this._dbs = [];
}
DbStore.prototype.emit = function(event, message, object, reset, filterDb) {
if(reset) {
while(this._dbs.length > 0) {
var db = this._dbs.shift();
// Only emit if there is a listener
if(db.listeners(event).length > 0) {
if(filterDb == null || filterDb.databaseName !== db.databaseName
|| filterDb.tag !== db.tag) {
db.emit(event, message, object);
}
}
}
} else {
for(var i = 0; i < this._dbs.length; i++) {
if(this._dbs[i].listeners(event).length > 0) {
if(filterDb == null || filterDb.databaseName !== this._dbs[i].databaseName
|| filterDb.tag !== this._dbs[i].tag) {
this._dbs[i].emit(event, message, object);
}
}
}
}
}
var Base = function Base() {
EventEmitter.call(this);
// Callback store is part of connection specification
if(Base._callBackStore == null) {
Base._callBackStore = new CallbackStore();
}
// Create a new callback store
this._callBackStore = new CallbackStore();
// All commands not being executed
this._commandsStore = new NonExecutedOperationStore(this);
// Create a new auth store
this.auth = new AuthStore();
// Contains all the dbs attached to this server config
this._dbStore = new DbStore();
}
/**
* @ignore
*/
inherits(Base, EventEmitter);
/**
* @ignore
*/
Base.prototype._apply_auths = function(db, callback) {
_apply_auths_serially(this, db, this.auth.toArray(), callback);
}
var _apply_auths_serially = function(self, db, auths, callback) {
if(auths.length == 0) return callback(null, null);
// Get the first auth
var auth = auths.shift();
var connections = self.allRawConnections();
var connectionsLeft = connections.length;
// Let's apply it to all raw connections
for(var i = 0; i < connections.length; i++) {
var options = {connection: connections[i]};
if(auth.authMechanism == 'GSSAPI') {
var connectionHandler = function(err, result) {
connectionsLeft = connectionsLeft - 1;
// If no more connections are left return
if(connectionsLeft == 0) {
return _apply_auths_serially(self, db, auths, callback);
}
}
// We have the kerberos library, execute auth process
if(process.platform == 'win32') {
mongodb_sspi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
} else {
mongodb_gssapi_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
}
} else if(auth.authMechanism == 'MONGODB-CR') {
mongodb_cr_authenticate(db, auth.username, auth.password, auth.authdb, options, callback);
}
}
}
/**
* Fire all the errors
* @ignore
*/
Base.prototype.__executeAllCallbacksWithError = function(err) {
// Check all callbacks
var keys = Object.keys(this._callBackStore._notReplied);
// For each key check if it's a callback that needs to be returned
for(var j = 0; j < keys.length; j++) {
var info = this._callBackStore._notReplied[keys[j]];
// Check if we have a chained command (findAndModify)
if(info && info['chained'] && Array.isArray(info['chained']) && info['chained'].length > 0) {
var chained = info['chained'];
// Only callback once and the last one is the right one
var finalCallback = chained.pop();
// Emit only the last event
this._callBackStore.emit(finalCallback, err, null);
// Put back the final callback to ensure we don't call all commands in the chain
chained.push(finalCallback);
// Remove all chained callbacks
for(var i = 0; i < chained.length; i++) {
delete this._callBackStore._notReplied[chained[i]];
}
// Remove the key
delete this._callBackStore._notReplied[keys[j]];
} else {
this._callBackStore.emit(keys[j], err, null);
// Remove the key
delete this._callBackStore._notReplied[keys[j]];
}
}
}
/**
* Fire all the errors
* @ignore
*/
Base.prototype.__executeAllServerSpecificErrorCallbacks = function(host, port, err) {
// Check all callbacks
var keys = Object.keys(this._callBackStore._notReplied);
// For each key check if it's a callback that needs to be returned
for(var j = 0; j < keys.length; j++) {
var info = this._callBackStore._notReplied[keys[j]];
if(info.connection) {
// Unpack the connection settings
var _host = info.connection.socketOptions.host;
var _port = info.connection.socketOptions.port;
// Check if we have a chained command (findAndModify)
if(info && info['chained']
&& Array.isArray(info['chained'])
&& info['chained'].length > 0
&& _port == port && _host == host) {
var chained = info['chained'];
// Only callback once and the last one is the right one
var finalCallback = chained.pop();
// Emit only the last event
this._callBackStore.emit(finalCallback, err, null);
// Put back the final callback to ensure we don't call all commands in the chain
chained.push(finalCallback);
// Remove all chained callbacks
for(var i = 0; i < chained.length; i++) {
delete this._callBackStore._notReplied[chained[i]];
}
// Remove the key
delete this._callBackStore._notReplied[keys[j]];
} else if(_port == port && _host == host) {
this._callBackStore.emit(keys[j], err, null);
// Remove the key
delete this._callBackStore._notReplied[keys[j]];
}
}
}
}
/**
* Register a handler
* @ignore
* @api private
*/
Base.prototype._registerHandler = function(db_command, raw, connection, exhaust, callback) {
// If we have an array of commands, chain them
var chained = Array.isArray(db_command);
// Check if we have exhausted
if(typeof exhaust == 'function') {
callback = exhaust;
exhaust = false;
}
// If they are chained we need to add a special handler situation
if(chained) {
// List off chained id's
var chainedIds = [];
// Add all id's
for(var i = 0; i < db_command.length; i++) chainedIds.push(db_command[i].getRequestId().toString());
// Register all the commands together
for(var i = 0; i < db_command.length; i++) {
var command = db_command[i];
// Add the callback to the store
this._callBackStore.once(command.getRequestId(), callback);
// Add the information about the reply
this._callBackStore._notReplied[command.getRequestId().toString()] = {start: new Date().getTime(), 'raw': raw, chained:chainedIds, connection:connection, exhaust:false};
}
} else {
// Add the callback to the list of handlers
this._callBackStore.once(db_command.getRequestId(), callback);
// Add the information about the reply
this._callBackStore._notReplied[db_command.getRequestId().toString()] = {start: new Date().getTime(), 'raw': raw, connection:connection, exhaust:exhaust};
}
}
/**
* Re-Register a handler, on the cursor id f.ex
* @ignore
* @api private
*/
Base.prototype._reRegisterHandler = function(newId, object, callback) {
// Add the callback to the list of handlers
this._callBackStore.once(newId, object.callback.listener);
// Add the information about the reply
this._callBackStore._notReplied[newId] = object.info;
}
/**
*
* @ignore
* @api private
*/
Base.prototype._callHandler = function(id, document, err) {
// If there is a callback peform it
if(this._callBackStore.listeners(id).length >= 1) {
// Get info object
var info = this._callBackStore._notReplied[id];
// Delete the current object
delete this._callBackStore._notReplied[id];
// Emit to the callback of the object
this._callBackStore.emit(id, err, document, info.connection);
}
}
/**
*
* @ignore
* @api private
*/
Base.prototype._hasHandler = function(id) {
// If there is a callback peform it
return this._callBackStore.listeners(id).length >= 1;
}
/**
*
* @ignore
* @api private
*/
Base.prototype._removeHandler = function(id) {
// Remove the information
if(this._callBackStore._notReplied[id] != null) delete this._callBackStore._notReplied[id];
// Remove the callback if it's registered
this._callBackStore.removeAllListeners(id);
// Force cleanup _events, node.js seems to set it as a null value
if(this._callBackStore._events != null) delete this._callBackStore._events[id];
}
/**
*
* @ignore
* @api private
*/
Base.prototype._findHandler = function(id) {
var info = this._callBackStore._notReplied[id];
// Return the callback
return {info:info, callback:(this._callBackStore.listeners(id).length >= 1) ? this._callBackStore.listeners(id)[0] : null}
}
/**
*
* @ignore
* @api private
*/
Base.prototype._emitAcrossAllDbInstances = function(server, filterDb, event, message, object, resetConnection) {
if(resetConnection) {
for(var i = 0; i < this._dbStore._dbs.length; i++) {
if(typeof this._dbStore._dbs[i].openCalled != 'undefined')
this._dbStore._dbs[i].openCalled = false;
}
}
// Fire event
this._dbStore.emit(event, message, object, resetConnection, filterDb);
}
exports.Base = Base;

View File

@ -0,0 +1,505 @@
var utils = require('./connection_utils'),
inherits = require('util').inherits,
net = require('net'),
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits,
binaryutils = require('../utils'),
tls = require('tls');
var Connection = exports.Connection = function(id, socketOptions) {
// Set up event emitter
EventEmitter.call(this);
// Store all socket options
this.socketOptions = socketOptions ? socketOptions : {host:'localhost', port:27017, domainSocket:false};
// Set keep alive default if not overriden
if(this.socketOptions.keepAlive == null && (process.platform !== "sunos" || process.platform !== "win32")) this.socketOptions.keepAlive = 100;
// Id for the connection
this.id = id;
// State of the connection
this.connected = false;
// Set if this is a domain socket
this.domainSocket = this.socketOptions.domainSocket;
//
// Connection parsing state
//
this.maxBsonSize = socketOptions.maxBsonSize ? socketOptions.maxBsonSize : Connection.DEFAULT_MAX_BSON_SIZE;
this.maxMessageSizeBytes = socketOptions.maxMessageSizeBytes ? socketOptions.maxMessageSizeBytes : Connection.DEFAULT_MAX_MESSAGE_SIZE;
// Contains the current message bytes
this.buffer = null;
// Contains the current message size
this.sizeOfMessage = 0;
// Contains the readIndex for the messaage
this.bytesRead = 0;
// Contains spill over bytes from additional messages
this.stubBuffer = 0;
// Just keeps list of events we allow
this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[], end:[]};
// Just keeps list of events we allow
resetHandlers(this, false);
}
// Set max bson size
Connection.DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4;
// Set default to max bson to avoid overflow or bad guesses
Connection.DEFAULT_MAX_MESSAGE_SIZE = Connection.DEFAULT_MAX_BSON_SIZE;
// Inherit event emitter so we can emit stuff wohoo
inherits(Connection, EventEmitter);
Connection.prototype.start = function() {
var self = this;
// If we have a normal connection
if(this.socketOptions.ssl) {
// Create new connection instance
if(this.domainSocket) {
this.connection = net.createConnection(this.socketOptions.host);
} else {
this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
}
if(this.logger != null && this.logger.doDebug){
this.logger.debug("opened connection", this.socketOptions);
}
// Set options on the socket
this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
// Work around for 0.4.X
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
// Set keep alive if defined
if(process.version.indexOf("v0.4") == -1) {
if(this.socketOptions.keepAlive > 0) {
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
} else {
this.connection.setKeepAlive(false);
}
}
// Check if the driver should validate the certificate
var validate_certificates = this.socketOptions.sslValidate == true ? true : false;
// Create options for the tls connection
var tls_options = {
socket: this.connection
, rejectUnauthorized: false
}
// If we wish to validate the certificate we have provided a ca store
if(validate_certificates) {
tls_options.ca = this.socketOptions.sslCA;
}
// If we have a certificate to present
if(this.socketOptions.sslCert) {
tls_options.cert = this.socketOptions.sslCert;
tls_options.key = this.socketOptions.sslKey;
}
// If the driver has been provided a private key password
if(this.socketOptions.sslPass) {
tls_options.passphrase = this.socketOptions.sslPass;
}
// Contains the cleartext stream
var cleartext = null;
// Attempt to establish a TLS connection to the server
try {
cleartext = tls.connect(this.socketOptions.port, this.socketOptions.host, tls_options, function() {
// If we have a ssl certificate validation error return an error
if(cleartext.authorizationError && validate_certificates) {
// Emit an error
return self.emit("error", cleartext.authorizationError, self, {ssl:true});
}
// Connect to the server
connectHandler(self)();
})
} catch(err) {
return self.emit("error", "SSL connection failed", self, {ssl:true});
}
// Save the output stream
this.writeSteam = cleartext;
// Set up data handler for the clear stream
cleartext.on("data", createDataHandler(this));
// Do any handling of end event of the stream
cleartext.on("end", endHandler(this));
cleartext.on("error", errorHandler(this));
// Handle any errors
this.connection.on("error", errorHandler(this));
// Handle timeout
this.connection.on("timeout", timeoutHandler(this));
// Handle drain event
this.connection.on("drain", drainHandler(this));
// Handle the close event
this.connection.on("close", closeHandler(this));
} else {
// Create new connection instance
if(this.domainSocket) {
this.connection = net.createConnection(this.socketOptions.host);
} else {
this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
}
if(this.logger != null && this.logger.doDebug){
this.logger.debug("opened connection", this.socketOptions);
}
// Set options on the socket
this.connection.setTimeout(this.socketOptions.connectTimeoutMS != null ? this.socketOptions.connectTimeoutMS : this.socketOptions.timeout);
// Work around for 0.4.X
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
// Set keep alive if defined
if(process.version.indexOf("v0.4") == -1) {
if(this.socketOptions.keepAlive > 0) {
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
} else {
this.connection.setKeepAlive(false);
}
}
// Set up write stream
this.writeSteam = this.connection;
// Add handlers
this.connection.on("error", errorHandler(this));
// Add all handlers to the socket to manage it
this.connection.on("connect", connectHandler(this));
// this.connection.on("end", endHandler(this));
this.connection.on("data", createDataHandler(this));
this.connection.on("timeout", timeoutHandler(this));
this.connection.on("drain", drainHandler(this));
this.connection.on("close", closeHandler(this));
}
}
// Check if the sockets are live
Connection.prototype.isConnected = function() {
return this.connected && !this.connection.destroyed && this.connection.writable && this.connection.readable;
}
// Write the data out to the socket
Connection.prototype.write = function(command, callback) {
try {
// If we have a list off commands to be executed on the same socket
if(Array.isArray(command)) {
for(var i = 0; i < command.length; i++) {
var binaryCommand = command[i].toBinary()
if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
return callback(new Error("Document exceeds maximum allowed bson size of " + this.maxBsonSize + " bytes"));
if(this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxMessageSizeBytes) {
return callback(new Error("Command exceeds maximum message size of " + this.maxMessageSizeBytes + " bytes"));
}
if(this.logger != null && this.logger.doDebug)
this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command[i]});
var r = this.writeSteam.write(binaryCommand);
}
} else {
var binaryCommand = command.toBinary()
if(!this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxBsonSize)
return callback(new Error("Document exceeds maximum allowed bson size of " + this.maxBsonSize + " bytes"));
if(this.socketOptions['disableDriverBSONSizeCheck'] && binaryCommand.length > this.maxMessageSizeBytes) {
return callback(new Error("Command exceeds maximum message size of " + this.maxMessageSizeBytes + " bytes"));
}
if(this.logger != null && this.logger.doDebug)
this.logger.debug("writing command to mongodb", {binary: binaryCommand, json: command});
var r = this.writeSteam.write(binaryCommand);
}
} catch (err) {
if(typeof callback === 'function') callback(err);
}
}
// Force the closure of the connection
Connection.prototype.close = function() {
// clear out all the listeners
resetHandlers(this, true);
// Add a dummy error listener to catch any weird last moment errors (and ignore them)
this.connection.on("error", function() {})
// destroy connection
this.connection.destroy();
if(this.logger != null && this.logger.doDebug){
this.logger.debug("closed connection", this.connection);
}
}
// Reset all handlers
var resetHandlers = function(self, clearListeners) {
self.eventHandlers = {error:[], connect:[], close:[], end:[], timeout:[], parseError:[], message:[]};
// If we want to clear all the listeners
if(clearListeners && self.connection != null) {
var keys = Object.keys(self.eventHandlers);
// Remove all listeners
for(var i = 0; i < keys.length; i++) {
self.connection.removeAllListeners(keys[i]);
}
}
}
//
// Handlers
//
// Connect handler
var connectHandler = function(self) {
return function(data) {
// Set connected
self.connected = true;
// Now that we are connected set the socket timeout
self.connection.setTimeout(self.socketOptions.socketTimeoutMS != null ? self.socketOptions.socketTimeoutMS : self.socketOptions.timeout);
// Emit the connect event with no error
self.emit("connect", null, self);
}
}
var createDataHandler = exports.Connection.createDataHandler = function(self) {
// We need to handle the parsing of the data
// and emit the messages when there is a complete one
return function(data) {
// Parse until we are done with the data
while(data.length > 0) {
// If we still have bytes to read on the current message
if(self.bytesRead > 0 && self.sizeOfMessage > 0) {
// Calculate the amount of remaining bytes
var remainingBytesToRead = self.sizeOfMessage - self.bytesRead;
// Check if the current chunk contains the rest of the message
if(remainingBytesToRead > data.length) {
// Copy the new data into the exiting buffer (should have been allocated when we know the message size)
data.copy(self.buffer, self.bytesRead);
// Adjust the number of bytes read so it point to the correct index in the buffer
self.bytesRead = self.bytesRead + data.length;
// Reset state of buffer
data = new Buffer(0);
} else {
// Copy the missing part of the data into our current buffer
data.copy(self.buffer, self.bytesRead, 0, remainingBytesToRead);
// Slice the overflow into a new buffer that we will then re-parse
data = data.slice(remainingBytesToRead);
// Emit current complete message
try {
var emitBuffer = self.buffer;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Emit the buffer
self.emit("message", emitBuffer, self);
} catch(err) {
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
sizeOfMessage:self.sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
}
} else {
// Stub buffer is kept in case we don't get enough bytes to determine the
// size of the message (< 4 bytes)
if(self.stubBuffer != null && self.stubBuffer.length > 0) {
// If we have enough bytes to determine the message size let's do it
if(self.stubBuffer.length + data.length > 4) {
// Prepad the data
var newData = new Buffer(self.stubBuffer.length + data.length);
self.stubBuffer.copy(newData, 0);
data.copy(newData, self.stubBuffer.length);
// Reassign for parsing
data = newData;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
} else {
// Add the the bytes to the stub buffer
var newStubBuffer = new Buffer(self.stubBuffer.length + data.length);
// Copy existing stub buffer
self.stubBuffer.copy(newStubBuffer, 0);
// Copy missing part of the data
data.copy(newStubBuffer, self.stubBuffer.length);
// Exit parsing loop
data = new Buffer(0);
}
} else {
if(data.length > 4) {
// Retrieve the message size
var sizeOfMessage = binaryutils.decodeUInt32(data, 0);
// If we have a negative sizeOfMessage emit error and return
if(sizeOfMessage < 0 || sizeOfMessage > self.maxBsonSize) {
var errorObject = {err:"socketHandler", trace:'', bin:self.buffer, parseState:{
sizeOfMessage: sizeOfMessage,
bytesRead: self.bytesRead,
stubBuffer: self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
return;
}
// Ensure that the size of message is larger than 0 and less than the max allowed
if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage > data.length) {
self.buffer = new Buffer(sizeOfMessage);
// Copy all the data into the buffer
data.copy(self.buffer, 0);
// Update bytes read
self.bytesRead = data.length;
// Update sizeOfMessage
self.sizeOfMessage = sizeOfMessage;
// Ensure stub buffer is null
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
} else if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage == data.length) {
try {
var emitBuffer = data;
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
// Emit the message
self.emit("message", emitBuffer, self);
} catch (err) {
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
sizeOfMessage:self.sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
} else if(sizeOfMessage <= 4 || sizeOfMessage > self.maxBsonSize) {
var errorObject = {err:"socketHandler", trace:null, bin:data, parseState:{
sizeOfMessage:sizeOfMessage,
bytesRead:0,
buffer:null,
stubBuffer:null}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
// Clear out the state of the parser
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Exit parsing loop
data = new Buffer(0);
} else {
try {
var emitBuffer = data.slice(0, sizeOfMessage);
// Reset state of buffer
self.buffer = null;
self.sizeOfMessage = 0;
self.bytesRead = 0;
self.stubBuffer = null;
// Copy rest of message
data = data.slice(sizeOfMessage);
// Emit the message
self.emit("message", emitBuffer, self);
} catch (err) {
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
sizeOfMessage:sizeOfMessage,
bytesRead:self.bytesRead,
stubBuffer:self.stubBuffer}};
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
// We got a parse Error fire it off then keep going
self.emit("parseError", errorObject, self);
}
}
} else {
// Create a buffer that contains the space for the non-complete message
self.stubBuffer = new Buffer(data.length)
// Copy the data to the stub buffer
data.copy(self.stubBuffer, 0);
// Exit parsing loop
data = new Buffer(0);
}
}
}
}
}
}
var endHandler = function(self) {
return function() {
// Set connected to false
self.connected = false;
// Emit end event
self.emit("end", {err: 'connection received Fin packet from [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
var timeoutHandler = function(self) {
return function() {
// Set connected to false
self.connected = false;
// Emit timeout event
self.emit("timeout", {err: 'connection to [' + self.socketOptions.host + ':' + self.socketOptions.port + '] timed out'}, self);
}
}
var drainHandler = function(self) {
return function() {
}
}
var errorHandler = function(self) {
return function(err) {
self.connection.destroy();
// Set connected to false
self.connected = false;
// Emit error
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
var closeHandler = function(self) {
return function(hadError) {
// If we have an error during the connection phase
if(hadError && !self.connected) {
// Set disconnected
self.connected = false;
// Emit error
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
} else {
// Set disconnected
self.connected = false;
// Emit close
self.emit("close", {err: 'connection closed to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
}
}
}
// Some basic defaults
Connection.DEFAULT_PORT = 27017;

View File

@ -0,0 +1,294 @@
var utils = require('./connection_utils'),
inherits = require('util').inherits,
net = require('net'),
timers = require('timers'),
EventEmitter = require('events').EventEmitter,
inherits = require('util').inherits,
MongoReply = require("../responses/mongo_reply").MongoReply,
Connection = require("./connection").Connection;
// Set processor, setImmediate if 0.10 otherwise nextTick
var processor = timers.setImmediate ? timers.setImmediate : process.nextTick;
processor = process.nextTick
var ConnectionPool = exports.ConnectionPool = function(host, port, poolSize, bson, socketOptions) {
if(typeof host !== 'string') {
throw new Error("host must be specified [" + host + "]");
}
// Set up event emitter
EventEmitter.call(this);
// Keep all options for the socket in a specific collection allowing the user to specify the
// Wished upon socket connection parameters
this.socketOptions = typeof socketOptions === 'object' ? socketOptions : {};
this.socketOptions.host = host;
this.socketOptions.port = port;
this.socketOptions.domainSocket = false;
this.bson = bson;
// PoolSize is always + 1 for special reserved "measurment" socket (like ping, stats etc)
this.poolSize = poolSize;
this.minPoolSize = Math.floor(this.poolSize / 2) + 1;
// Check if the host is a socket
if(host.match(/^\//)) {
this.socketOptions.domainSocket = true;
} else if(typeof port === 'string') {
try {
port = parseInt(port, 10);
} catch(err) {
new Error("port must be specified or valid integer[" + port + "]");
}
} else if(typeof port !== 'number') {
throw new Error("port must be specified [" + port + "]");
}
// Set default settings for the socket options
utils.setIntegerParameter(this.socketOptions, 'timeout', 0);
// Delay before writing out the data to the server
utils.setBooleanParameter(this.socketOptions, 'noDelay', true);
// Delay before writing out the data to the server
utils.setIntegerParameter(this.socketOptions, 'keepAlive', 0);
// Set the encoding of the data read, default is binary == null
utils.setStringParameter(this.socketOptions, 'encoding', null);
// Allows you to set a throttling bufferSize if you need to stop overflows
utils.setIntegerParameter(this.socketOptions, 'bufferSize', 0);
// Internal structures
this.openConnections = [];
// Assign connection id's
this.connectionId = 0;
// Current index for selection of pool connection
this.currentConnectionIndex = 0;
// The pool state
this._poolState = 'disconnected';
// timeout control
this._timeout = false;
// Time to wait between connections for the pool
this._timeToWait = 10;
}
inherits(ConnectionPool, EventEmitter);
ConnectionPool.prototype.setMaxBsonSize = function(maxBsonSize) {
if(maxBsonSize == null){
maxBsonSize = Connection.DEFAULT_MAX_BSON_SIZE;
}
for(var i = 0; i < this.openConnections.length; i++) {
this.openConnections[i].maxBsonSize = maxBsonSize;
}
}
ConnectionPool.prototype.setMaxMessageSizeBytes = function(maxMessageSizeBytes) {
if(maxMessageSizeBytes == null){
maxMessageSizeBytes = Connection.DEFAULT_MAX_MESSAGE_SIZE;
}
for(var i = 0; i < this.openConnections.length; i++) {
this.openConnections[i].maxMessageSizeBytes = maxMessageSizeBytes;
}
}
// Start a function
var _connect = function(_self) {
// return new function() {
// Create a new connection instance
var connection = new Connection(_self.connectionId++, _self.socketOptions);
// Set logger on pool
connection.logger = _self.logger;
// Connect handler
connection.on("connect", function(err, connection) {
// Add connection to list of open connections
_self.openConnections.push(connection);
// If the number of open connections is equal to the poolSize signal ready pool
if(_self.openConnections.length === _self.poolSize && _self._poolState !== 'disconnected') {
// Set connected
_self._poolState = 'connected';
// Emit pool ready
_self.emit("poolReady");
} else if(_self.openConnections.length < _self.poolSize) {
// Wait a little bit of time to let the close event happen if the server closes the connection
// so we don't leave hanging connections around
if(typeof _self._timeToWait == 'number') {
setTimeout(function() {
// If we are still connecting (no close events fired in between start another connection)
if(_self._poolState == 'connecting') {
_connect(_self);
}
}, _self._timeToWait);
} else {
processor(function() {
// If we are still connecting (no close events fired in between start another connection)
if(_self._poolState == 'connecting') {
_connect(_self);
}
});
}
}
});
var numberOfErrors = 0
// Error handler
connection.on("error", function(err, connection, error_options) {
numberOfErrors++;
// If we are already disconnected ignore the event
if(_self._poolState != 'disconnected' && _self.listeners("error").length > 0) {
_self.emit("error", err, connection, error_options);
}
// Close the connection
connection.close();
// Set pool as disconnected
_self._poolState = 'disconnected';
// Stop the pool
_self.stop();
});
// Close handler
connection.on("close", function() {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("close").length > 0) {
_self.emit("close");
}
// Set disconnected
_self._poolState = 'disconnected';
// Stop
_self.stop();
});
// Timeout handler
connection.on("timeout", function(err, connection) {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("timeout").length > 0) {
_self.emit("timeout", err);
}
// Close the connection
connection.close();
// Set disconnected
_self._poolState = 'disconnected';
_self.stop();
});
// Parse error, needs a complete shutdown of the pool
connection.on("parseError", function() {
// If we are already disconnected ignore the event
if(_self._poolState !== 'disconnected' && _self.listeners("parseError").length > 0) {
_self.emit("parseError", new Error("parseError occured"));
}
// Set disconnected
_self._poolState = 'disconnected';
_self.stop();
});
connection.on("message", function(message) {
_self.emit("message", message);
});
// Start connection in the next tick
connection.start();
// }();
}
// Start method, will throw error if no listeners are available
// Pass in an instance of the listener that contains the api for
// finding callbacks for a given message etc.
ConnectionPool.prototype.start = function() {
var markerDate = new Date().getTime();
var self = this;
if(this.listeners("poolReady").length == 0) {
throw "pool must have at least one listener ready that responds to the [poolReady] event";
}
// Set pool state to connecting
this._poolState = 'connecting';
this._timeout = false;
_connect(self);
}
// Restart a connection pool (on a close the pool might be in a wrong state)
ConnectionPool.prototype.restart = function() {
// Close all connections
this.stop(false);
// Now restart the pool
this.start();
}
// Stop the connections in the pool
ConnectionPool.prototype.stop = function(removeListeners) {
removeListeners = removeListeners == null ? true : removeListeners;
// Set disconnected
this._poolState = 'disconnected';
// Clear all listeners if specified
if(removeListeners) {
this.removeAllEventListeners();
}
// Close all connections
for(var i = 0; i < this.openConnections.length; i++) {
this.openConnections[i].close();
}
// Clean up
this.openConnections = [];
}
// Check the status of the connection
ConnectionPool.prototype.isConnected = function() {
// return this._poolState === 'connected';
return this.openConnections.length > 0 && this.openConnections[0].isConnected();
}
// Checkout a connection from the pool for usage, or grab a specific pool instance
ConnectionPool.prototype.checkoutConnection = function(id) {
var index = (this.currentConnectionIndex++ % (this.openConnections.length));
var connection = this.openConnections[index];
return connection;
}
ConnectionPool.prototype.getAllConnections = function() {
return this.openConnections;
}
// Remove all non-needed event listeners
ConnectionPool.prototype.removeAllEventListeners = function() {
this.removeAllListeners("close");
this.removeAllListeners("error");
this.removeAllListeners("timeout");
this.removeAllListeners("connect");
this.removeAllListeners("end");
this.removeAllListeners("parseError");
this.removeAllListeners("message");
this.removeAllListeners("poolReady");
}

View File

@ -0,0 +1,23 @@
exports.setIntegerParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "number" && object[field] !== parseInt(object[field], 10)) {
throw "object field [" + field + "] must be a numeric integer value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}
exports.setBooleanParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "boolean") {
throw "object field [" + field + "] must be a boolean value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}
exports.setStringParameter = function(object, field, defaultValue) {
if(object[field] == null) {
object[field] = defaultValue;
} else if(typeof object[field] !== "string") {
throw "object field [" + field + "] must be a string value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
}
}

View File

@ -0,0 +1,474 @@
var ReadPreference = require('./read_preference').ReadPreference
, Base = require('./base').Base
, Server = require('./server').Server
, inherits = require('util').inherits;
/**
* Mongos constructor provides a connection to a mongos proxy including failover to additional servers
*
* Options
* - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), connectTimeoutMS:(number), socketTimeoutMS:(number))
* - **ha** {Boolean, default:true}, turn on high availability, attempts to reconnect to down proxies
* - **haInterval** {Number, default:2000}, time between each replicaset status check.
*
* @class Represents a Mongos connection with failover to backup proxies
* @param {Array} list of mongos server objects
* @param {Object} [options] additional options for the mongos connection
*/
var Mongos = function Mongos(servers, options) {
// Set up basic
if(!(this instanceof Mongos))
return new Mongos(servers, options);
// Set up event emitter
Base.call(this);
// Throw error on wrong setup
if(servers == null || !Array.isArray(servers) || servers.length == 0)
throw new Error("At least one mongos proxy must be in the array");
// Ensure we have at least an empty options object
this.options = options == null ? {} : options;
// Set default connection pool options
this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
// Enabled ha
this.haEnabled = this.options['ha'] == null ? true : this.options['ha'];
this._haInProgress = false;
// How often are we checking for new servers in the replicaset
this.mongosStatusCheckInterval = this.options['haInterval'] == null ? 1000 : this.options['haInterval'];
// Save all the server connections
this.servers = servers;
// Servers we need to attempt reconnect with
this.downServers = [];
// Emit open setup
this.emitOpen = this.options.emitOpen || true;
// Just contains the current lowest ping time and server
this.lowestPingTimeServer = null;
this.lowestPingTime = 0;
// Connection timeout
this._connectTimeoutMS = this.socketOptions.connectTimeoutMS
? this.socketOptions.connectTimeoutMS
: 1000;
// Add options to servers
for(var i = 0; i < this.servers.length; i++) {
var server = this.servers[i];
server._callBackStore = this._callBackStore;
server.auto_reconnect = false;
// Default empty socket options object
var socketOptions = {host: server.host, port: server.port};
// If a socket option object exists clone it
if(this.socketOptions != null) {
var keys = Object.keys(this.socketOptions);
for(var k = 0; k < keys.length;k++) socketOptions[keys[i]] = this.socketOptions[keys[i]];
}
// Set socket options
server.socketOptions = socketOptions;
}
}
/**
* @ignore
*/
inherits(Mongos, Base);
/**
* @ignore
*/
Mongos.prototype.isMongos = function() {
return true;
}
/**
* @ignore
*/
Mongos.prototype.connect = function(db, options, callback) {
if('function' === typeof options) callback = options, options = {};
if(options == null) options = {};
if(!('function' === typeof callback)) callback = null;
var self = this;
// Keep reference to parent
this.db = db;
// Set server state to connecting
this._serverState = 'connecting';
// Number of total servers that need to initialized (known servers)
this._numberOfServersLeftToInitialize = this.servers.length;
// Connect handler
var connectHandler = function(_server) {
return function(err, result) {
self._numberOfServersLeftToInitialize = self._numberOfServersLeftToInitialize - 1;
if(self._numberOfServersLeftToInitialize == 0) {
// Start ha function if it exists
if(self.haEnabled) {
// Setup the ha process
if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId);
self._replicasetTimeoutId = setInterval(self.mongosCheckFunction, self.mongosStatusCheckInterval);
}
// Set the mongos to connected
self._serverState = "connected";
// Emit the open event
if(self.emitOpen)
self.db.emit("open", null, self.db);
// Callback
callback(null, self.db);
}
}
};
// Error handler
var errorOrCloseHandler = function(_server) {
return function(err, result) {
var validServers = [];
// Execute all the callbacks with errors
self.__executeAllCallbacksWithError(err);
// Check if we have the server
var found = false;
// Save the down server if it does not already exists
for(var i = 0; i < self.downServers.length; i++) {
if(self.downServers[i].host == _server.host && self.downServers[i].port == _server.port) {
found = true;
break;
}
}
if(!found)
self.downServers.push(_server);
// Remove the current server from the list
for(var i = 0; i < self.servers.length; i++) {
if(!(self.servers[i].host == _server.host && self.servers[i].port == _server.port) && self.servers[i].isConnected()) {
validServers.push(self.servers[i]);
}
}
// Set current list of servers
self.servers = validServers;
// Emit close across all the attached db instances
if(self.servers.length == 0) {
self._dbStore.emit("close", new Error("mongos disconnected, no valid proxies contactable over tcp"), null, true);
}
}
}
// Mongo function
this.mongosCheckFunction = function() {
if(self._haInProgress) return;
// If all servers are down we are done
if(self.servers.length == 0) return;
// Check that at least one server is available
var alldown = true;
for(var i = 0; i < self.servers.length; i++) {
if(self.servers[i].isConnected()) {
alldown = false;
break;
}
}
// All servers are down
if(alldown) return;
// Set as not waiting for check event
self._haInProgress = true;
// Check downed servers
if(self.downServers.length > 0) {
var numberOfServersLeft = self.downServers.length;
// Iterate over all the downed servers
for(var i = 0; i < self.downServers.length; i++) {
// Pop a downed server
var downServer = self.downServers.pop();
// Set up the connection options for a Mongos
var options = {
auto_reconnect: false,
returnIsMasterResults: true,
slaveOk: true,
poolSize: downServer.poolSize,
socketOptions: {
connectTimeoutMS: self._connectTimeoutMS,
socketTimeoutMS: self._socketTimeoutMS
}
}
// Create a new server object
var newServer = new Server(downServer.host, downServer.port, options);
// Setup the connection function
var connectFunction = function(_db, _server, _options, _callback) {
return function() {
// Attempt to connect
_server.connect(_db, _options, function(err, result) {
numberOfServersLeft = numberOfServersLeft - 1;
if(err) {
return _callback(err, _server);
} else {
// Set the new server settings
_server._callBackStore = self._callBackStore;
// Add server event handlers
_server.on("close", errorOrCloseHandler(_server));
_server.on("timeout", errorOrCloseHandler(_server));
_server.on("error", errorOrCloseHandler(_server));
// Get a read connection
var _connection = _server.checkoutReader();
// Get the start time
var startTime = new Date().getTime();
// Execute ping command to mark each server with the expected times
self.db.command({ping:1}
, {failFast:true, connection:_connection}, function(err, result) {
// Get the start time
var endTime = new Date().getTime();
// Mark the server with the ping time
_server.runtimeStats['pingMs'] = endTime - startTime;
// Sort the servers on runtime so the first server always is the closest one
self.servers.sort(function(a, b) {
return a.runtimeStats['pingMs'] > b.runtimeStats['pingMs'];
});
// Callback
return _callback(null, _server);
});
}
});
}
}
// Attempt to connect to the database
connectFunction(self.db, newServer, options, function(err, _server) {
// If we have an error
if(err) {
self.downServers.push(_server);
}
// Connection function
var connectionFunction = function(_auth, _connection, _callback) {
var pending = _auth.length();
for(var j = 0; j < pending; j++) {
// Get the auth object
var _auth = _auth.get(j);
// Unpack the parameter
var username = _auth.username;
var password = _auth.password;
var options = {
authMechanism: _auth.authMechanism
, authSource: _auth.authdb
, connection: _connection
};
// If we have changed the service name
if(_auth.gssapiServiceName)
options.gssapiServiceName = _auth.gssapiServiceName;
// Hold any error
var _error = null;
// Authenticate against the credentials
self.db.authenticate(username, password, options, function(err, result) {
_error = err != null ? err : _error;
// Adjust the pending authentication
pending = pending - 1;
// Finished up
if(pending == 0) _callback(_error ? _error : null, _error ? false : true);
});
}
}
// Run auths against the connections
if(self.auth.length() > 0) {
var connections = _server.allRawConnections();
var pendingAuthConn = connections.length;
// No connections we are done
if(connections.length == 0) {
// Set ha done
if(numberOfServersLeft == 0) {
self._haInProgress = false;
}
}
// Final error object
var finalError = null;
// Go over all the connections
for(var j = 0; j < connections.length; j++) {
// Execute against all the connections
connectionFunction(self.auth, connections[j], function(err, result) {
// Pending authentication
pendingAuthConn = pendingAuthConn - 1 ;
// Save error if any
finalError = err ? err : finalError;
// If we are done let's finish up
if(pendingAuthConn == 0) {
// Set ha done
if(numberOfServersLeft == 0) {
self._haInProgress = false;
}
if(finalError) {
return self.downServers.push(_server);
}
// Push to list of valid server
self.servers.push(_server);
}
});
}
} else {
self.servers.push(_server);
// Set ha done
if(numberOfServersLeft == 0) {
self._haInProgress = false;
}
}
})();
}
} else {
self._haInProgress = false;
}
}
// Connect all the server instances
for(var i = 0; i < this.servers.length; i++) {
// Get the connection
var server = this.servers[i];
server.mongosInstance = this;
// Add server event handlers
server.on("close", errorOrCloseHandler(server));
server.on("timeout", errorOrCloseHandler(server));
server.on("error", errorOrCloseHandler(server));
// Configuration
var options = {
slaveOk: true,
poolSize: server.poolSize,
socketOptions: { connectTimeoutMS: self._connectTimeoutMS },
returnIsMasterResults: true
}
// Connect the instance
server.connect(self.db, options, connectHandler(server));
}
}
/**
* @ignore
* Just return the currently picked active connection
*/
Mongos.prototype.allServerInstances = function() {
return this.servers;
}
/**
* Always ourselves
* @ignore
*/
Mongos.prototype.setReadPreference = function() {}
/**
* @ignore
*/
Mongos.prototype.allRawConnections = function() {
// Neeed to build a complete list of all raw connections, start with master server
var allConnections = [];
// Add all connections
for(var i = 0; i < this.servers.length; i++) {
allConnections = allConnections.concat(this.servers[i].allRawConnections());
}
// Return all the conections
return allConnections;
}
/**
* @ignore
*/
Mongos.prototype.isConnected = function() {
return this._serverState == "connected";
}
/**
* @ignore
*/
Mongos.prototype.canWrite = Mongos.prototype.isConnected;
/**
* @ignore
*/
Mongos.prototype.canRead = Mongos.prototype.isConnected;
/**
* @ignore
*/
Mongos.prototype.isDestroyed = function() {
return this._serverState == 'destroyed';
}
/**
* @ignore
*/
Mongos.prototype.checkoutWriter = function() {
if(this.servers.length == 0) return null;
return this.servers[0].checkoutWriter();
}
/**
* @ignore
*/
Mongos.prototype.checkoutReader = function(read) {
// If we have a read preference object unpack it
if(read != null && typeof read == 'object' && read['_type'] == 'ReadPreference') {
// Validate if the object is using a valid mode
if(!read.isValid()) throw new Error("Illegal readPreference mode specified, " + read.mode);
} else if(!ReadPreference.isValid(read)) {
throw new Error("Illegal readPreference mode specified, " + read);
}
if(this.servers.length == 0) return null;
return this.servers[0].checkoutWriter();
}
/**
* @ignore
*/
Mongos.prototype.close = function(callback) {
var self = this;
// Set server status as disconnected
this._serverState = 'destroyed';
// Number of connections to close
var numberOfConnectionsToClose = self.servers.length;
// If we have a ha process running kill it
if(self._replicasetTimeoutId != null) clearInterval(self._replicasetTimeoutId);
self._replicasetTimeoutId = null;
// Close all proxy connections
for(var i = 0; i < self.servers.length; i++) {
self.servers[i].close(function(err, result) {
numberOfConnectionsToClose = numberOfConnectionsToClose - 1;
// Callback if we have one defined
if(numberOfConnectionsToClose == 0 && typeof callback == 'function') {
callback(null);
}
});
}
}
/**
* @ignore
* Return the used state
*/
Mongos.prototype._isUsed = function() {
return this._used;
}
exports.Mongos = Mongos;

View File

@ -0,0 +1,67 @@
/**
* A class representation of the Read Preference.
*
* Read Preferences
* - **ReadPreference.PRIMARY**, Read from primary only. All operations produce an error (throw an exception where applicable) if primary is unavailable. Cannot be combined with tags (This is the default.).
* - **ReadPreference.PRIMARY_PREFERRED**, Read from primary if available, otherwise a secondary.
* - **ReadPreference.SECONDARY**, Read from secondary if available, otherwise error.
* - **ReadPreference.SECONDARY_PREFERRED**, Read from a secondary if available, otherwise read from the primary.
* - **ReadPreference.NEAREST**, All modes read from among the nearest candidates, but unlike other modes, NEAREST will include both the primary and all secondaries in the random selection.
*
* @class Represents a Read Preference.
* @param {String} the read preference type
* @param {Object} tags
* @return {ReadPreference}
*/
var ReadPreference = function(mode, tags) {
if(!(this instanceof ReadPreference))
return new ReadPreference(mode, tags);
this._type = 'ReadPreference';
this.mode = mode;
this.tags = tags;
}
/**
* @ignore
*/
ReadPreference.isValid = function(_mode) {
return (_mode == ReadPreference.PRIMARY || _mode == ReadPreference.PRIMARY_PREFERRED
|| _mode == ReadPreference.SECONDARY || _mode == ReadPreference.SECONDARY_PREFERRED
|| _mode == ReadPreference.NEAREST
|| _mode == true || _mode == false);
}
/**
* @ignore
*/
ReadPreference.prototype.isValid = function(mode) {
var _mode = typeof mode == 'string' ? mode : this.mode;
return ReadPreference.isValid(_mode);
}
/**
* @ignore
*/
ReadPreference.prototype.toObject = function() {
var object = {mode:this.mode};
if(this.tags != null) {
object['tags'] = this.tags;
}
return object;
}
/**
* @ignore
*/
ReadPreference.PRIMARY = 'primary';
ReadPreference.PRIMARY_PREFERRED = 'primaryPreferred';
ReadPreference.SECONDARY = 'secondary';
ReadPreference.SECONDARY_PREFERRED = 'secondaryPreferred';
ReadPreference.NEAREST = 'nearest'
/**
* @ignore
*/
exports.ReadPreference = ReadPreference;

View File

@ -0,0 +1,411 @@
var DbCommand = require('../../commands/db_command').DbCommand
, format = require('util').format;
var HighAvailabilityProcess = function(replset, options) {
this.replset = replset;
this.options = options;
this.server = null;
this.state = HighAvailabilityProcess.INIT;
this.selectedIndex = 0;
}
HighAvailabilityProcess.INIT = 'init';
HighAvailabilityProcess.RUNNING = 'running';
HighAvailabilityProcess.STOPPED = 'stopped';
HighAvailabilityProcess.prototype.start = function() {
var self = this;
if(this.replset._state
&& Object.keys(this.replset._state.addresses).length == 0) {
if(this.server) this.server.close();
this.state = HighAvailabilityProcess.STOPPED;
return;
}
if(this.server) this.server.close();
// Start the running
this._haProcessInProcess = false;
this.state = HighAvailabilityProcess.RUNNING;
// Get all possible reader servers
var candidate_servers = this.replset._state.getAllReadServers();
if(candidate_servers.length == 0) {
return;
}
// Select a candidate server for the connection
var server = candidate_servers[this.selectedIndex % candidate_servers.length];
this.selectedIndex = this.selectedIndex + 1;
// Unpack connection options
var connectTimeoutMS = self.options.connectTimeoutMS || 10000;
var socketTimeoutMS = self.options.socketTimeoutMS || 30000;
// Just ensure we don't have a full cycle dependency
var Db = require('../../db').Db
var Server = require('../server').Server;
// Set up a new server instance
var newServer = new Server(server.host, server.port, {
auto_reconnect: false
, returnIsMasterResults: true
, poolSize: 1
, socketOptions: {
connectTimeoutMS: connectTimeoutMS,
socketTimeoutMS: socketTimeoutMS,
keepAlive: 100
}
, ssl: this.options.ssl
, sslValidate: this.options.sslValidate
, sslCA: this.options.sslCA
, sslCert: this.options.sslCert
, sslKey: this.options.sslKey
, sslPass: this.options.sslPass
});
// Create new dummy db for app
self.db = new Db('local', newServer, {w:1});
// Set up the event listeners
newServer.once("error", _handle(this, newServer));
newServer.once("close", _handle(this, newServer));
newServer.once("timeout", _handle(this, newServer));
newServer.name = format("%s:%s", server.host, server.port);
// Let's attempt a connection over here
newServer.connect(self.db, function(err, result, _server) {
if(self.state == HighAvailabilityProcess.STOPPED) {
_server.close();
}
if(err) {
// Close the server
_server.close();
// Check if we can even do HA (is there anything running)
if(Object.keys(self.replset._state.addresses).length == 0) {
return;
}
// Let's boot the ha timeout settings
setTimeout(function() {
self.start();
}, self.options.haInterval);
} else {
self.server = _server;
// Let's boot the ha timeout settings
setTimeout(_timeoutHandle(self), self.options.haInterval);
}
});
}
HighAvailabilityProcess.prototype.stop = function() {
this.state = HighAvailabilityProcess.STOPPED;
if(this.server) this.server.close();
}
var _timeoutHandle = function(self) {
return function() {
if(self.state == HighAvailabilityProcess.STOPPED) {
// Stop all server instances
for(var name in self.replset._state.addresses) {
self.replset._state.addresses[name].close();
delete self.replset._state.addresses[name];
}
// Finished pinging
return;
}
// If the server is connected
if(self.server.isConnected() && !self._haProcessInProcess) {
// Start HA process
self._haProcessInProcess = true;
// Execute is master command
self.db._executeQueryCommand(DbCommand.createIsMasterCommand(self.db),
{failFast:true, connection: self.server.checkoutReader()}
, function(err, res) {
if(err) {
self.server.close();
return setTimeout(_timeoutHandle(self), self.options.haInterval);
}
// Master document
var master = res.documents[0];
var hosts = master.hosts || [];
var reconnect_servers = [];
var state = self.replset._state;
// console.log("==================================== HA ISMASTER")
// console.dir(master)
// We are in recovery mode, let's remove the current server
if(!master.ismaster
&& !master.secondary
&& state.addresses[master.me]) {
self.server.close();
state.addresses[master.me].close();
delete state.secondaries[master.me];
return setTimeout(_timeoutHandle(self), self.options.haInterval);
}
// For all the hosts let's check that we have connections
for(var i = 0; i < hosts.length; i++) {
var host = hosts[i];
// Check if we need to reconnect to a server
if(state.addresses[host] == null) {
reconnect_servers.push(host);
} else if(state.addresses[host] && !state.addresses[host].isConnected()) {
state.addresses[host].close();
delete state.secondaries[host];
reconnect_servers.push(host);
}
if((master.primary && state.master == null)
|| (master.primary && state.master.name != master.primary)) {
// Locate the primary and set it
if(state.addresses[master.primary]) {
if(state.master) state.master.close();
delete state.secondaries[master.primary];
state.master = state.addresses[master.primary];
}
// Set up the changes
if(state.master != null && state.master.isMasterDoc != null) {
state.master.isMasterDoc.ismaster = true;
state.master.isMasterDoc.secondary = false;
} else if(state.master != null) {
state.master.isMasterDoc = master;
state.master.isMasterDoc.ismaster = true;
state.master.isMasterDoc.secondary = false;
}
// Execute any waiting commands (queries or writes)
self.replset._commandsStore.execute_queries();
self.replset._commandsStore.execute_writes();
}
}
// Let's reconnect to any server needed
if(reconnect_servers.length > 0) {
_reconnect_servers(self, reconnect_servers);
} else {
self._haProcessInProcess = false
return setTimeout(_timeoutHandle(self), self.options.haInterval);
}
});
} else if(!self.server.isConnected()) {
setTimeout(function() {
return self.start();
}, self.options.haInterval);
} else {
setTimeout(_timeoutHandle(self), self.options.haInterval);
}
}
}
var _reconnect_servers = function(self, reconnect_servers) {
if(reconnect_servers.length == 0) {
self._haProcessInProcess = false
return setTimeout(_timeoutHandle(self), self.options.haInterval);
}
// Unpack connection options
var connectTimeoutMS = self.options.connectTimeoutMS || 10000;
var socketTimeoutMS = self.options.socketTimeoutMS || 30000;
// Server class
var Db = require('../../db').Db
var Server = require('../server').Server;
// Get the host
var host = reconnect_servers.shift();
// Split it up
var _host = host.split(":")[0];
var _port = parseInt(host.split(":")[1], 10);
// Set up a new server instance
var newServer = new Server(_host, _port, {
auto_reconnect: false
, returnIsMasterResults: true
, poolSize: self.options.poolSize
, socketOptions: {
connectTimeoutMS: connectTimeoutMS,
socketTimeoutMS: socketTimeoutMS
}
, ssl: self.options.ssl
, sslValidate: self.options.sslValidate
, sslCA: self.options.sslCA
, sslCert: self.options.sslCert
, sslKey: self.options.sslKey
, sslPass: self.options.sslPass
});
// Create new dummy db for app
var db = new Db('local', newServer, {w:1});
var state = self.replset._state;
// Set up the event listeners
newServer.once("error", _repl_set_handler("error", self.replset, newServer));
newServer.once("close", _repl_set_handler("close", self.replset, newServer));
newServer.once("timeout", _repl_set_handler("timeout", self.replset, newServer));
// Set shared state
newServer.name = host;
newServer._callBackStore = self.replset._callBackStore;
newServer.replicasetInstance = self.replset;
newServer.enableRecordQueryStats(self.replset.recordQueryStats);
// Let's attempt a connection over here
newServer.connect(db, function(err, result, _server) {
if(self.state == HighAvailabilityProcess.STOPPED) {
_server.close();
}
// If we connected let's check what kind of server we have
if(!err) {
_apply_auths(self, db, _server, function(err, result) {
if(err) {
_server.close();
// Process the next server
return setTimeout(function() {
_reconnect_servers(self, reconnect_servers);
}, self.options.haInterval);
}
var doc = _server.isMasterDoc;
// Fire error on any unknown callbacks for this server
self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err);
if(doc.ismaster) {
if(state.secondaries[doc.me]) {
delete state.secondaries[doc.me];
}
// Override any server in list of addresses
state.addresses[doc.me] = _server;
// Set server as master
state.master = _server;
// Execute any waiting writes
self.replset._commandsStore.execute_writes();
} else if(doc.secondary) {
state.secondaries[doc.me] = _server;
// Override any server in list of addresses
state.addresses[doc.me] = _server;
// Execute any waiting reads
self.replset._commandsStore.execute_queries();
} else {
_server.close();
}
// Set any tags on the instance server
_server.name = doc.me;
_server.tags = doc.tags;
// Process the next server
setTimeout(function() {
_reconnect_servers(self, reconnect_servers);
}, self.options.haInterval);
});
} else {
_server.close();
self.replset.__executeAllServerSpecificErrorCallbacks(_server.socketOptions.host, _server.socketOptions.port, err);
setTimeout(function() {
_reconnect_servers(self, reconnect_servers);
}, self.options.haInterval);
}
});
}
var _apply_auths = function(self, _db, _server, _callback) {
if(self.replset.auth.length() == 0) return _callback(null);
// Apply any authentication needed
if(self.replset.auth.length() > 0) {
var pending = self.replset.auth.length();
var connections = _server.allRawConnections();
var pendingAuthConn = connections.length;
// Connection function
var connectionFunction = function(_auth, _connection, __callback) {
var pending = _auth.length();
for(var j = 0; j < pending; j++) {
// Get the auth object
var _auth = _auth.get(j);
// Unpack the parameter
var username = _auth.username;
var password = _auth.password;
var options = {
authMechanism: _auth.authMechanism
, authSource: _auth.authdb
, connection: _connection
};
// If we have changed the service name
if(_auth.gssapiServiceName)
options.gssapiServiceName = _auth.gssapiServiceName;
// Hold any error
var _error = null;
// Authenticate against the credentials
_db.authenticate(username, password, options, function(err, result) {
_error = err != null ? err : _error;
// Adjust the pending authentication
pending = pending - 1;
// Finished up
if(pending == 0) __callback(_error ? _error : null, _error ? false : true);
});
}
}
// Final error object
var finalError = null;
// Iterate over all the connections
for(var i = 0; i < connections.length; i++) {
connectionFunction(self.replset.auth, connections[i], function(err, result) {
// Pending authentication
pendingAuthConn = pendingAuthConn - 1 ;
// Save error if any
finalError = err ? err : finalError;
// If we are done let's finish up
if(pendingAuthConn == 0) {
_callback(null);
}
});
}
}
}
var _handle = function(self, server) {
return function(err) {
server.close();
}
}
var _repl_set_handler = function(event, self, server) {
var ReplSet = require('./repl_set').ReplSet;
return function(err, doc) {
server.close();
// The event happened to a primary
// Remove it from play
if(self._state.isPrimary(server)) {
self._state.master == null;
self._serverState = ReplSet.REPLSET_READ_ONLY;
} else if(self._state.isSecondary(server)) {
delete self._state.secondaries[server.name];
}
// Unpack variables
var host = server.socketOptions.host;
var port = server.socketOptions.port;
// Fire error on any unknown callbacks
self.__executeAllServerSpecificErrorCallbacks(host, port, err);
}
}
exports.HighAvailabilityProcess = HighAvailabilityProcess;

View File

@ -0,0 +1,126 @@
var PingStrategy = require('./strategies/ping_strategy').PingStrategy
, StatisticsStrategy = require('./strategies/statistics_strategy').StatisticsStrategy
, ReadPreference = require('../read_preference').ReadPreference;
var Options = function(options) {
options = options || {};
this._options = options;
this.ha = options.ha || true;
this.haInterval = options.haInterval || 2000;
this.reconnectWait = options.reconnectWait || 1000;
this.retries = options.retries || 30;
this.rs_name = options.rs_name;
this.socketOptions = options.socketOptions || {};
this.readPreference = options.readPreference;
this.readSecondary = options.read_secondary;
this.poolSize = options.poolSize == null ? 5 : options.poolSize;
this.strategy = options.strategy || 'ping';
this.secondaryAcceptableLatencyMS = options.secondaryAcceptableLatencyMS || 15;
this.connectArbiter = options.connectArbiter || false;
this.connectWithNoPrimary = options.connectWithNoPrimary || false;
this.logger = options.logger;
this.ssl = options.ssl || false;
this.sslValidate = options.sslValidate || false;
this.sslCA = options.sslCA;
this.sslCert = options.sslCert;
this.sslKey = options.sslKey;
this.sslPass = options.sslPass;
this.emitOpen = options.emitOpen || true;
}
Options.prototype.init = function() {
if(this.sslValidate && (!Array.isArray(this.sslCA) || this.sslCA.length == 0)) {
throw new Error("The driver expects an Array of CA certificates in the sslCA parameter when enabling sslValidate");
}
// Make sure strategy is one of the two allowed
if(this.strategy != null && (this.strategy != 'ping' && this.strategy != 'statistical' && this.strategy != 'none'))
throw new Error("Only ping or statistical strategies allowed");
if(this.strategy == null) this.strategy = 'ping';
// Set logger if strategy exists
if(this.strategyInstance) this.strategyInstance.logger = this.logger;
// Unpack read Preference
var readPreference = this.readPreference;
// Validate correctness of Read preferences
if(readPreference != null) {
if(readPreference != ReadPreference.PRIMARY && readPreference != ReadPreference.PRIMARY_PREFERRED
&& readPreference != ReadPreference.SECONDARY && readPreference != ReadPreference.SECONDARY_PREFERRED
&& readPreference != ReadPreference.NEAREST && typeof readPreference != 'object' && readPreference['_type'] != 'ReadPreference') {
throw new Error("Illegal readPreference mode specified, " + readPreference);
}
this.readPreference = readPreference;
} else {
this.readPreference = null;
}
// Ensure read_secondary is set correctly
if(this.readSecondary != null)
this.readSecondary = this.readPreference == ReadPreference.PRIMARY
|| this.readPreference == false
|| this.readPreference == null ? false : true;
// Ensure correct slave set
if(this.readSecondary) this.slaveOk = true;
// Set up logger if any set
this.logger = this.logger != null
&& (typeof this.logger.debug == 'function')
&& (typeof this.logger.error == 'function')
&& (typeof this.logger.debug == 'function')
? this.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
// Connection timeout
this.connectTimeoutMS = this.socketOptions.connectTimeoutMS
? this.socketOptions.connectTimeoutMS
: 1000;
// Socket connection timeout
this.socketTimeoutMS = this.socketOptions.socketTimeoutMS
? this.socketOptions.socketTimeoutMS
: 30000;
}
Options.prototype.decorateAndClean = function(servers, callBackStore) {
var self = this;
// var de duplicate list
var uniqueServers = {};
// De-duplicate any servers in the seed list
for(var i = 0; i < servers.length; i++) {
var server = servers[i];
// If server does not exist set it
if(uniqueServers[server.host + ":" + server.port] == null) {
uniqueServers[server.host + ":" + server.port] = server;
}
}
// Let's set the deduplicated list of servers
var finalServers = [];
// Add the servers
for(var key in uniqueServers) {
finalServers.push(uniqueServers[key]);
}
finalServers.forEach(function(server) {
// Ensure no server has reconnect on
server.options.auto_reconnect = false;
// Set up ssl options
server.ssl = self.ssl;
server.sslValidate = self.sslValidate;
server.sslCA = self.sslCA;
server.sslCert = self.sslCert;
server.sslKey = self.sslKey;
server.sslPass = self.sslPass;
server.poolSize = self.poolSize;
// Set callback store
server._callBackStore = callBackStore;
});
return finalServers;
}
exports.Options = Options;

Some files were not shown because too many files have changed in this diff Show More