Socket
Socket
Sign inDemoInstall

mongoose

Package Overview
Dependencies
Maintainers
0
Versions
888
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mongoose - npm Package Compare versions

Comparing version 1.4.0 to 1.5.0

support/node-mongodb-native/deps/nodeunit/.npmignore

6

docs/virtuals.md

@@ -34,3 +34,3 @@ Virtual attributes

.get( function () {
return this.name.first + this.name.last;
return this.name.first + ' ' + this.name.last;
});

@@ -45,3 +45,3 @@

function () {
return this.name.first + this.name.last;
return this.name.first + ' ' + this.name.last;
}

@@ -59,3 +59,3 @@

.get( function () {
return this.name.first + this.name.last;
return this.name.first + ' ' + this.name.last;
})

@@ -62,0 +62,0 @@ .set( function (setFullNameTo) {

1.5.0 / 2011-06-27
===================
* changed; saving without a callback no longer ignores the error (@bnoguchi)
* changed; hook-js version bump to 0.1.9
* changed; node-mongodb-native version bumped to 0.9.6.1 - When .remove() doesn't
return an error, null is no longer passed.
* fixed; two memory leaks (@justmoon)
* added; sparse index support
* added; more ObjectId conditionals (gt, lt, gte, lte) (@phillyqueso)
* added; options are now passed in model#remote (@JerryLuke)
1.4.0 / 2011-06-10

@@ -3,0 +15,0 @@ ===================

@@ -79,2 +79,3 @@

}
this.queue = [];
return this;

@@ -81,0 +82,0 @@ };

@@ -648,2 +648,4 @@

}
}, function (err) {
this.emit('error', err);
}).pre('save', function validation (next) {

@@ -650,0 +652,0 @@ return self.validate.call(self, next);

@@ -96,20 +96,3 @@

if (!this.buffer) {
// if the spec is an array, use -native (old way)
if (fields.constructor != Object)
return oldEnsureIndex.apply(this, arguments);
fn = fn || noop;
// transform fields dict into lame array
var fieldsArr = [];
for (var i in fields)
fieldsArr.push([i, fields[i]]);
if (options && Object.keys(options).length){
if (options.unique)
return oldEnsureIndex.call(this, fieldsArr, true, fn);
else if (fn != noop)
fn(new Error('This driver only implements unique indexes'));
} else
oldEnsureIndex.call(this, fieldsArr, fn);
return oldEnsureIndex.apply(this, arguments);
}

@@ -116,0 +99,0 @@ };

@@ -292,3 +292,3 @@

exports.version = '1.4.0';
exports.version = '1.5.0';

@@ -295,0 +295,0 @@ /**

@@ -66,2 +66,12 @@

function makeSaveHandler(promise, self) {
return function (err) {
if (err) return promise.error(err);
promise.complete(self);
self.emit('save', self);
promise = null;
self = null;
};
};
Model.prototype.save = function (fn) {

@@ -72,7 +82,3 @@ var promise = new Promise(fn)

function complete (err) {
if (err) return promise.error(err);
promise.complete(self);
self.emit('save', self);
};
var complete = makeSaveHandler(promise, self);

@@ -255,2 +261,4 @@ // support for safe mode

});
}, function (err) {
this.emit('error', err);
});

@@ -301,3 +309,4 @@

indexes.forEach(function (index) {
self.collection.ensureIndex(index[0], index[1], function(){
self.collection.ensureIndex(index[0], index[1], function (err) {
if (err) return self.emit(err);
--count || self.emit('index');

@@ -304,0 +313,0 @@ });

@@ -881,6 +881,8 @@ var utils = require('./utils')

this.op = 'remove';
var model = this.model;
var model = this.model
, options = this._optionsForExec(model);
this.cast(model);
var castQuery = this._conditions;
model.collection.remove(castQuery, callback);
model.collection.remove(castQuery, options, callback);
return this;

@@ -887,0 +889,0 @@ };

@@ -1,2 +0,1 @@

/**

@@ -76,2 +75,6 @@ * Module dependencies.

, '$nin': handleArray
, '$gt': handleSingle
, '$lt': handleSingle
, '$gte': handleSingle
, '$lte': handleSingle
};

@@ -78,0 +81,0 @@ ObjectId.prototype.castForQuery = function ($conditional, val) {

{
"name": "mongoose"
, "description": "Mongoose MongoDB ORM"
, "version": "1.4.0"
, "version": "1.5.0"
, "author": "Guillermo Rauch <guillermo@learnboost.com>"
, "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"]
, "dependencies": {
"hooks": "0.1.7"
"hooks": "0.1.9"
}
, "devDependencies": {
"should": ">=0.2.1"
"should": "0.2.1"
}

@@ -13,0 +13,0 @@ , "directories": { "lib": "./lib/mongoose" }

@@ -11,21 +11,23 @@ Mongoose 1.0

var Comments = new Schema({
title : String
, body : String
, date : Date
});
```javascript
var Comments = new Schema({
title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
, comments : [Comments]
, meta : {
votes : Number
, favs : Number
}
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
, comments : [Comments]
, meta : {
votes : Number
, favs : Number
}
});
mongoose.model('BlogPost', BlogPost);
mongoose.model('BlogPost', BlogPost);
```

@@ -36,15 +38,22 @@ ## Installation

$ npm install mongoose
```bash
$ npm install mongoose
```
Otherwise, you can check it in your repository and then expose it:
$ git clone git@github.com:LearnBoost/mongoose.git support/mongoose/
```bash
$ git clone git@github.com:LearnBoost/mongoose.git support/mongoose/
```
```javascript
// in your code
require.paths.unshift('support/mongoose/lib')
```
// in your code
require.paths.unshift('support/mongoose/lib')
Then you can `require` it:
Then you can require it:
```javascript
require('mongoose')
```
require('mongoose')
## Connecting to MongoDB

@@ -59,5 +68,7 @@

var mongoose = require('mongoose');
```javascript
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_database');
mongoose.connect('mongodb://localhost/my_database');
```

@@ -76,11 +87,13 @@ Once connected, the `open` event is fired on the `Connection` instance. If

var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
```javascript
var Schema = mongoose.Schema
, ObjectId = Schema.ObjectId;
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
});
var BlogPost = new Schema({
author : ObjectId
, title : String
, body : String
, date : Date
});
```

@@ -102,19 +115,21 @@ Aside from defining the structure of your documents and the types of data you're

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 }
});
```javascript
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 }
});
// a setter
Comment.path('name').set(function (v) {
return v.capitalize();
});
// a setter
Comment.path('name').set(function (v) {
return v.capitalize();
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```

@@ -129,17 +144,23 @@ Take a look at the example in `examples/schema.js` for an end-to-end example of

var myModel = mongoose.model('ModelName');
```javascript
var myModel = mongoose.model('ModelName');
```
We can then instantiate it, and save it:
var instance = new myModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
```javascript
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
});
```javascript
myModel.find({}, function (err, docs) {
// docs.forEach
});
```

@@ -153,3 +174,5 @@ You can also `findOne`, `findById`, `update`, etc. For more details check out

comments: [Comments]
```
comments: [Comments]
```

@@ -159,25 +182,29 @@ Where `Comments` is a `Schema` we created. This means that creating embedded

// retrieve my model
var BlogPost = mongoose.model('BlogPost');
```javascript
// retrieve my model
var BlogPost = mongoose.model('BlogPost');
// create a blog post
var post = new BlogPost();
// create a blog post
var post = new BlogPost();
// create a comment
post.comments.push({ title: 'My comment' });
// create a comment
post.comments.push({ title: 'My comment' });
post.save(function (err) {
if (!err) console.log('Success!');
});
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
});
}
```javascript
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```

@@ -205,5 +232,7 @@ Embedded documents enjoy all the same features as your models. Defaults,

.pre(method, function (next, methodArg1, methodArg2, ...) {
// ...
})
```javascript
.pre(method, function (next, methodArg1, methodArg2, ...) {
// ...
})
```

@@ -219,8 +248,10 @@ They're executed one after the other, when each middleware calls `next`.

Parallel middleware offer more fine-grained flow control, and are defined
like
like:
```javascript
.pre(method, true, function (next, done, methodArg1, methodArg2) {
// ...
})
```
.pre(method, true, function (next, done, methodArg1, methodArg2) {
// ...
})
Parallel middleware can `next()` immediately, but the final argument will be

@@ -236,12 +267,14 @@ called when all the parallel middleware have called `done()`.

schema.pre('save', function (next) {
// something goes wrong
next(new Error('something went wrong'));
});
```javascript
schema.pre('save', function (next) {
// something goes wrong
next(new Error('something went wrong'));
});
// later...
// later...
myModel.save(function (err) {
// err can come from a middleware
});
myModel.save(function (err) {
// err can come from a middleware
});
```

@@ -310,2 +343,3 @@ ### Intercepting and mutating method arguments

- [mongoose-dbref](https://github.com/goulash1971/mongoose-dbref) - Adds DBRef support
- [mongoose-joins](https://github.com/goulash1971/mongoose-joins) - Adds simple join support

@@ -312,0 +346,0 @@ ## Contributing to Mongoose

@@ -10,3 +10,3 @@ require.paths.unshift('../lib');

GridStore = require('mongodb').GridStore,
sys = require('sys');
sys = require('util');

@@ -13,0 +13,0 @@ var simulated_buffer = new Buffer(1024*1000*10).toString();

@@ -8,6 +8,7 @@ require.paths.unshift('../lib');

Collection = require('mongodb').Collection,
sys = require('sys');
sys = require('util'),
debug = require('util').debug;
var BSON = require('bson');
var db = new Db('streaming_benchmark', new Server("127.0.0.1", 27017, {auto_reconnect: true}), {})
var db = new Db('streaming_benchmark', new Server("127.0.0.1", 27017, {auto_reconnect: true, poolSize:4}), {})
// Set native deserializer

@@ -25,4 +26,4 @@ db.bson_deserializer = BSON;

// Add documents
for(var i = 0; i < 100000; i++) {
// for(var i = 0; i < 1000; i++) {
// for(var i = 0; i < 100000; i++) {
for(var i = 0; i < 10000; i++) {
collection.save({'i':i, 'a':i, 'c':i, 'd':{'i':i}}, function(err, result){});

@@ -43,3 +44,3 @@ }

count++;
if ((count%10000)==0) sys.puts("recs:" + count + " :: " +
if ((count%1000)==0) sys.puts("recs:" + count + " :: " +
((new Date().getTime() - started_at)/1000) + "seconds");

@@ -46,0 +47,0 @@ });

GLOBAL.DEBUG = true;
sys = require("sys");
debug = require('util').debug,
inspect = require('util').inspect,
test = require("assert");

@@ -23,3 +25,3 @@

// Erase all records in collection
collection.remove(function(err, collection) {
collection.remove({}, function(err, r) {
db.admin(function(err, admin) {

@@ -39,3 +41,2 @@

cursor.toArray(function(err, items) {
// Stop profiling

@@ -47,5 +48,5 @@ admin.setProfilingLevel('off', function(err, level) {

// Validate returns a hash if all is well or return an error has if there is a
// Validate returns a hash if all is well or return an error hash if there is a
// problem.
admin.validatCollection(collection.collectionName, function(err, result) {
admin.validateCollection(collection.collectionName, function(err, result) {
sys.puts(result.result);

@@ -52,0 +53,0 @@ db.close();

GLOBAL.DEBUG = true;
sys = require("sys");
sys = require("sys"),
debug = require('util').debug,
inspect = require('util').inspect,
test = require("assert");

@@ -9,3 +11,2 @@

Server = require('../lib/mongodb').Server,
// BSON = require('../lib/mongodb').BSONPure;
BSON = require('../lib/mongodb').BSONNative;

@@ -20,5 +21,5 @@

db.dropDatabase(function(err, result) {
db.collection('test', function(err, collection) {
db.collection('test', function(err, collection) {
// Erase all records from the collection, if any
collection.remove(function(err, collection) {
collection.remove({}, function(err, result) {
// Insert 3 records

@@ -25,0 +26,0 @@ for(var i = 0; i < 3; i++) {

require.paths.unshift("../../lib");
var sys = require('sys'),
var sys = require('util'),
debug = require('util').debug,
inspect = require('util').inspect,
Buffer = require('buffer').Buffer,

@@ -22,196 +24,212 @@ BSON = require('./bson').BSON,

sys.puts("=== EXCEUTING TEST_BSON ===");
sys.puts("=== EXECUTING TEST_BSON ===");
// Long data type tests
var l2_string = Long2.fromNumber(100);
var l_string = Long.fromNumber(100);
assert.equal(l_string.toNumber(), l2_string.toNumber());
// // Long data type tests
// var l2_string = Long2.fromNumber(100);
// var l_string = Long.fromNumber(100);
// assert.equal(l_string.toNumber(), l2_string.toNumber());
//
// var l2_string = Long2.fromNumber(9223372036854775807).toString();
// var l_string = Long.fromNumber(9223372036854775807).toString();
// assert.equal(l_string, l2_string);
//
// l2_string = Long2.fromNumber(9223372036800).toString();
// l_string = Long.fromNumber(9223372036800).toString();
// assert.equal(l_string, l2_string);
//
// l2_string = Long2.fromNumber(2355).toString();
// l_string = Long.fromNumber(2355).toString();
// assert.equal(l_string, l2_string);
//
// l_string = Long.fromNumber(-9223372036854775807).toString();
// l2_string = Long2.fromNumber(-9223372036854775807).toString();
// assert.equal(l_string, l2_string);
//
// l2_string = Long2.fromNumber(-2355).toString();
// l_string = Long.fromNumber(-2355).toString();
// assert.equal(l_string, l2_string);
//
// l2_string = Long2.fromNumber(-1).toString();
// l_string = Long.fromNumber(-1).toString();
// assert.equal(l_string, l2_string);
//
// l2_string = Long2.fromNumber(1).toString();
// l_string = Long.fromNumber(1).toString();
// assert.equal(l_string, l2_string);
//
// var a = Long2.fromNumber(10);
// assert.equal(10, a);
//
// var a = Long2.fromNumber(9223372036854775807);
// assert.equal(9223372036854775807, a);
//
// // Simple serialization and deserialization test for a Single String value
// var simple_string_serialized = BSON.serialize({doc:'Serialize'});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple integer serialization/deserialization test, including testing boundary conditions
// var simple_string_serialized = BSON.serialize({doc:-1});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// var simple_string_serialized = BSON.serialize({doc:2147483648});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// var simple_string_serialized = BSON.serialize({doc:-2147483648});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization test for a Long value
// var simple_string_serialized = BSON.serialize({doc:Long2.fromNumber(9223372036854775807)});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// var simple_string_serialized = BSON.serialize({doc:Long2.fromNumber(-9223372036854775807)});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization for a Float value
// var simple_string_serialized = BSON.serialize({doc:2222.3333});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// var simple_string_serialized = BSON.serialize({doc:-2222.3333});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization for a null value
// var simple_string_serialized = BSON.serialize({doc:null});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization for a boolean value
// var simple_string_serialized = BSON.serialize({doc:true});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization for a date value
// var date = new Date();
// var simple_string_serialized = BSON.serialize({doc:date});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
//
// // Simple serialization and deserialization for a boolean value
// var simple_string_serialized = BSON.serialize({doc:/abcd/mi});
// assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
// assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
//
// var simple_string_serialized = BSON.serialize({doc:/abcd/});
// assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
// assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
//
// // Simple serialization and deserialization for a objectId value
// var simple_string_serialized = BSON.serialize({doc:new ObjectID2()});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
//
// // // Simple serialization and deserialization for a Binary value
// var binary = new Binary2();
// var string = 'binstring'
// for(var index = 0; index < string.length; index++) { binary.put(string.charAt(index)); }
// var simple_string_serialized = BSON.serialize({doc:binary});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.value(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.value());
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.value(), BSON.deserialize(simple_string_serialized).doc.value());
//
// // Simple serialization and deserialization for a Code value
// var code = new Code2('this.a > i', {'i': 1});
// var code2 = new Code('this.a > i', {'i': 1});
// var simple_string_serialized_2 = BSONJS.serialize({doc:code2});
// var simple_string_serialized = BSON.serialize({doc:code});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc.scope, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.scope);
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc.code, BSON.deserialize(simple_string_serialized).doc.code);
//
// // Simple serialization and deserialization for an Object
// var simple_string_serialized = BSON.serialize({doc:{a:1, b:{c:2}}});
// var simple_string_serialized_2 = BSONJS.serialize({doc:{a:1, b:{c:2}}});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc);
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(simple_string_serialized).doc);
//
// // Simple serialization and deserialization for an Array
// var simple_string_serialized = BSON.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]});
// var simple_string_serialized_2 = BSONJS.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]});
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc);
// assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(simple_string_serialized).doc);
//
// // Simple serialization and deserialization for a DBRef
// var oid = new ObjectID2()
// var simple_string_serialized = BSONJS.serialize({doc:new DBRef('namespace', oid, 'integration_tests_')});
// var simple_string_serialized_2 = BSON.serialize({doc:new DBRef2('namespace', oid, 'integration_tests_')});
//
// // Ensure we have the same values for the dbref
// var object_js = BSONJS.deserialize(simple_string_serialized_2);
// var object_c = BSON.deserialize(simple_string_serialized);
// assert.equal(object_js.doc.namespace, object_c.doc.namespace);
// assert.equal(object_js.doc.oid.toHexString(), object_c.doc.oid.toHexString());
// assert.equal(object_js.doc.db, object_c.doc.db);
//
// // Serialized document
// var bytes = [47,0,0,0,2,110,97,109,101,0,6,0,0,0,80,97,116,116,121,0,16,97,103,101,0,34,0,0,0,7,95,105,100,0,76,100,12,23,11,30,39,8,89,0,0,1,0];
// var serialized_data = '';
// // Convert to chars
// for(var i = 0; i < bytes.length; i++) {
// serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]);
// }
// var object = BSON.deserialize(serialized_data);
// assert.equal('Patty', object.name)
// assert.equal(34, object.age)
// assert.equal('4c640c170b1e270859000001', object._id.toHexString())
//
// // Serialize utf8
// var doc = { "name" : "本荘由利地域に洪水警報", "name1" : "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "name2" : "abcdedede"};
// var simple_string_serialized = BSON.serialize(doc);
// var object = BSON.deserialize(simple_string_serialized);
// assert.equal(doc.name, object.name)
// assert.equal(doc.name1, object.name1)
// assert.equal(doc.name2, object.name2)
//
// // Serialize object with array
// var doc = {b:[1, 2, 3]};
// var simple_string_serialized = BSON.serialize(doc);
// var simple_string_serialized_2 = BSONJS.serialize(doc);
// var object = BSON.deserialize(simple_string_serialized);
// assert.deepEqual(doc, object)
//
// // Test equality of an object ID
// var object_id = new ObjectID2();
// var object_id_2 = new ObjectID2();
// assert.ok(object_id.equals(object_id));
// assert.ok(!(object_id.equals(object_id_2)))
var l2_string = Long2.fromNumber(9223372036854775807).toString();
var l_string = Long.fromNumber(9223372036854775807).toString();
assert.equal(l_string, l2_string);
// Test same serialization for Object ID
var object_id = new ObjectID();
var object_id2 = ObjectID2.createFromHexString(object_id.toString())
l2_string = Long2.fromNumber(9223372036800).toString();
l_string = Long.fromNumber(9223372036800).toString();
assert.equal(l_string, l2_string);
var simple_string_serialized = BSONJS.serialize({doc:object_id});
var simple_string_serialized_2 = BSON.serialize({doc:object_id2});
l2_string = Long2.fromNumber(2355).toString();
l_string = Long.fromNumber(2355).toString();
assert.equal(l_string, l2_string);
// assert.deepEqual(simple_string_serialized_2.toString(), simple_string_serialized_2.toString());
assert.equal(simple_string_serialized_2.length, simple_string_serialized.length);
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
var object = BSONJS.deserialize(simple_string_serialized_2);
var object2 = BSON.deserialize(simple_string_serialized);
assert.deepEqual(object, object2);
l_string = Long.fromNumber(-9223372036854775807).toString();
l2_string = Long2.fromNumber(-9223372036854775807).toString();
assert.equal(l_string, l2_string);
// Force garbage collect
global.gc();
l2_string = Long2.fromNumber(-2355).toString();
l_string = Long.fromNumber(-2355).toString();
assert.equal(l_string, l2_string);
l2_string = Long2.fromNumber(-1).toString();
l_string = Long.fromNumber(-1).toString();
assert.equal(l_string, l2_string);
l2_string = Long2.fromNumber(1).toString();
l_string = Long.fromNumber(1).toString();
assert.equal(l_string, l2_string);
var a = Long2.fromNumber(10);
assert.equal(10, a);
var a = Long2.fromNumber(9223372036854775807);
assert.equal(9223372036854775807, a);
// Simple serialization and deserialization test for a Single String value
var simple_string_serialized = BSON.serialize({doc:'Serialize'});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple integer serialization/deserialization test, including testing boundary conditions
var simple_string_serialized = BSON.serialize({doc:-1});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
var simple_string_serialized = BSON.serialize({doc:2147483648});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
var simple_string_serialized = BSON.serialize({doc:-2147483648});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization test for a Long value
var simple_string_serialized = BSON.serialize({doc:Long2.fromNumber(9223372036854775807)});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
var simple_string_serialized = BSON.serialize({doc:Long2.fromNumber(-9223372036854775807)});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization for a Float value
var simple_string_serialized = BSON.serialize({doc:2222.3333});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
var simple_string_serialized = BSON.serialize({doc:-2222.3333});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization for a null value
var simple_string_serialized = BSON.serialize({doc:null});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization for a boolean value
var simple_string_serialized = BSON.serialize({doc:true});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization for a date value
var date = new Date();
var simple_string_serialized = BSON.serialize({doc:date});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')));
assert.deepEqual(BSONJS.deserialize(simple_string_serialized), BSON.deserialize(simple_string_serialized));
// Simple serialization and deserialization for a boolean value
var simple_string_serialized = BSON.serialize({doc:/abcd/mi});
assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
var simple_string_serialized = BSON.serialize({doc:/abcd/});
assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
assert.equal(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
// Simple serialization and deserialization for a objectId value
var simple_string_serialized = BSON.serialize({doc:new ObjectID2()});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString());
assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.toString(), BSON.deserialize(simple_string_serialized).doc.toString());
// Simple serialization and deserialization for a Binary value
var binary = new Binary2();
var string = 'binstring'
for(var index = 0; index < string.length; index++) { binary.put(string.charAt(index)); }
var simple_string_serialized = BSON.serialize({doc:binary});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.value(), BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.value());
assert.deepEqual(BSONJS.deserialize(simple_string_serialized).doc.value(), BSON.deserialize(simple_string_serialized).doc.value());
// Simple serialization and deserialization for a Code value
var code = new Code2('this.a > i', {'i': 1});
var code2 = new Code('this.a > i', {'i': 1});
var simple_string_serialized_2 = BSONJS.serialize({doc:code2});
var simple_string_serialized = BSON.serialize({doc:code});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc.scope, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.scope);
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc.code, BSON.deserialize(simple_string_serialized).doc.code);
// Simple serialization and deserialization for an Object
var simple_string_serialized = BSON.serialize({doc:{a:1, b:{c:2}}});
var simple_string_serialized_2 = BSONJS.serialize({doc:{a:1, b:{c:2}}});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc);
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(simple_string_serialized).doc);
// Simple serialization and deserialization for an Array
var simple_string_serialized = BSON.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]});
var simple_string_serialized_2 = BSONJS.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]});
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(new Buffer(simple_string_serialized, 'binary')).doc);
assert.deepEqual(BSONJS.deserialize(simple_string_serialized_2).doc, BSON.deserialize(simple_string_serialized).doc);
// Simple serialization and deserialization for a DBRef
var oid = new ObjectID2()
var simple_string_serialized = BSONJS.serialize({doc:new DBRef('namespace', oid, 'integration_tests_')});
var simple_string_serialized_2 = BSON.serialize({doc:new DBRef2('namespace', oid, 'integration_tests_')});
// Ensure we have the same values for the dbref
var object_js = BSONJS.deserialize(simple_string_serialized_2);
var object_c = BSON.deserialize(simple_string_serialized);
assert.equal(object_js.doc.namespace, object_c.doc.namespace);
assert.equal(object_js.doc.oid.toHexString(), object_c.doc.oid.toHexString());
assert.equal(object_js.doc.db, object_c.doc.db);
// Serialized document
var bytes = [47,0,0,0,2,110,97,109,101,0,6,0,0,0,80,97,116,116,121,0,16,97,103,101,0,34,0,0,0,7,95,105,100,0,76,100,12,23,11,30,39,8,89,0,0,1,0];
var serialized_data = '';
// Convert to chars
for(var i = 0; i < bytes.length; i++) {
serialized_data = serialized_data + BinaryParser.fromByte(bytes[i]);
}
var object = BSON.deserialize(serialized_data);
assert.equal('Patty', object.name)
assert.equal(34, object.age)
assert.equal('4c640c170b1e270859000001', object._id.toHexString())
// Serialize utf8
var doc = { "name" : "本荘由利地域に洪水警報", "name1" : "öüóőúéáűíÖÜÓŐÚÉÁŰÍ", "name2" : "abcdedede"};
var simple_string_serialized = BSON.serialize(doc);
var object = BSON.deserialize(simple_string_serialized);
assert.equal(doc.name, object.name)
assert.equal(doc.name1, object.name1)
assert.equal(doc.name2, object.name2)
// Serialize object with array
var doc = {b:[1, 2, 3]};
var simple_string_serialized = BSON.serialize(doc);
var simple_string_serialized_2 = BSONJS.serialize(doc);
var object = BSON.deserialize(simple_string_serialized);
assert.deepEqual(doc, object)
// Test equality of an object ID
var object_id = new ObjectID2();
var object_id_2 = new ObjectID2();
assert.ok(object_id.equals(object_id));
assert.ok(!(object_id.equals(object_id_2)))
require.paths.unshift("../../lib");
var sys = require('sys'),
var sys = require('util'),
fs = require('fs'),

@@ -17,3 +17,3 @@ Buffer = require('buffer').Buffer,

sys.puts("=== EXCEUTING TEST_FULL_BSON ===");
sys.puts("=== EXECUTING TEST_FULL_BSON ===");

@@ -169,3 +169,3 @@ // Should Correctly Deserialize object

// Should Correctly Serialize and Deserialize a big Binary object
var data = fs.readFileSync("../../integration/test_gs_weird_bug.png", 'binary');
var data = fs.readFileSync("../../test/gridstore/test_gs_weird_bug.png", 'binary');
var bin = new Binary()

@@ -172,0 +172,0 @@ bin.write(data)

var Collection = require('./collection').Collection,
Cursor = require('./cursor').Cursor,
DbCommand = require('./commands/db_command').DbCommand;
DbCommand = require('./commands/db_command').DbCommand,
debug = require('util').debug,
inspect = require('util').inspect;

@@ -12,16 +14,15 @@ var Admin = exports.Admin = function(db) {

var command = {buildinfo:1};
var databaseName = self.db.databaseName;
self.db.databaseName = 'admin';
this.db.executeDbCommand(command, function(err, doc) {
this.command(command, function(err, doc) {
if(err != null) return callback(err, null);
return callback(null, doc.documents[0]);
});
// Ensure change before event loop executes
self.db.databaseName = databaseName;
}
Admin.prototype.profilingLevel = function(callback) {
var self = this;
var command = {profile:-1};
this.db.executeDbCommand(command, function(err, doc) {
this.command(command, function(err, doc) {
doc = doc.documents[0];
if(err == null && (doc.ok == 1 || doc.was.constructor == Numeric)) {

@@ -44,5 +45,18 @@ var was = doc.was;

Admin.prototype.authenticate = function(username, password, callback) {
var self = this;
var databaseName = this.db.databaseName;
this.db.databaseName = 'admin';
this.db.authenticate(username, password, function(err, result) {
self.db.databaseName = databaseName;
return callback(err, result);
})
}
Admin.prototype.setProfilingLevel = function(level, callback) {
var self = this;
var command = {};
var profile = 0;
if(level == "off") {

@@ -55,13 +69,13 @@ profile = 0;

} else {
callback(new Error("Error: illegal profiling level value " + level));
return;
return callback(new Error("Error: illegal profiling level value " + level));
}
command['profile'] = profile;
this.db.executeDbCommand(command, function(err, doc) {
this.command(command, function(err, doc) {
doc = doc.documents[0];
if(err == null && (doc.ok == 1 || doc.was.constructor == Numeric)) {
callback(null, level);
return callback(null, level);
} else {
err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
}

@@ -72,24 +86,41 @@ });

Admin.prototype.profilingInfo = function(callback) {
var self = this;
var databaseName = this.db.databaseName;
this.db.databaseName = 'admin';
new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}).toArray(function(err, items) {
callback(err, items);
});
return callback(err, items);
});
self.db.databaseName = databaseName;
};
Admin.prototype.validatCollection = function(collectionName, callback) {
Admin.prototype.command = function(command, callback) {
var self = this;
// Execute a command
this.db.executeDbAdminCommand(command, function(err, result) {
// Ensure change before event loop executes
return callback(err, result);
});
}
Admin.prototype.validateCollection = function(collectionName, callback) {
var self = this;
var command = {validate: collectionName};
this.db.executeDbCommand(command, function(err, doc) {
if(err != null) return callback(err, null);
doc = doc.documents[0];
if(err != null) {
callback(err, null);
} else if(doc.ok == 0) {
callback(new Error("Error with validate command"), null);
if(doc.ok == 0) {
return callback(new Error("Error with validate command"), null);
} else if(doc.result.constructor != String) {
callback(new Error("Error with validation data"), null);
return callback(new Error("Error with validation data"), null);
} else if(doc.result.match(/exception|corrupt/) != null) {
callback(new Error("Error: invalid collection " + collectionName), null);
return callback(new Error("Error: invalid collection " + collectionName), null);
} else {
callback(null, doc);
return callback(null, doc);
}
});
};

@@ -1,11 +0,22 @@

var sys = require('sys');
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/binary-parser [v1.0]
/**
* Module dependencies.
*/
var sys = require('util');
/**
* Binary Parser.
* Jonas Raoni Soares Silva
* http://jsfromhell.com/classes/binary-parser [v1.0]
*/
var chr = String.fromCharCode;
var maxBits = [];
for(var i = 0; i<64; i++)
for (var i = 0; i < 64; i++) {
maxBits[i] = Math.pow(2, i);
}
var p = exports.BinaryParser = function( bigEndian, allowExceptions ){
function BinaryParser (bigEndian, allowExceptions) {
this.bigEndian = bigEndian;

@@ -15,138 +26,154 @@ this.allowExceptions = allowExceptions;

var Buffer = exports.BinaryParser.Buffer = function( bigEndian, buffer ){
this.bigEndian = bigEndian || 0;
this.buffer = [];
this.setBuffer( buffer );
};
BinaryParser.warn = function warn (msg) {
if (this.allowExceptions) {
throw new Error(msg);
}
Buffer.prototype.setBuffer = function( data ){
if( data ){
for( var l, i = l = data.length, b = this.buffer = new Array( l ); i; b[l - i] = data.charCodeAt( --i ) );
this.bigEndian && b.reverse();
}
return 1;
};
Buffer.prototype.hasNeededBits = function( neededBits ){
return this.buffer.length >= -( -neededBits >> 3 );
};
BinaryParser.decodeFloat = function decodeFloat (data, precisionBits, exponentBits) {
var b = new this.Buffer(this.bigEndian, data);
Buffer.prototype.checkBuffer = function( neededBits ){
if( !this.hasNeededBits( neededBits ) )
throw new Error( "checkBuffer::missing bytes" );
};
b.checkBuffer(precisionBits + exponentBits + 1);
Buffer.prototype.readBits = function( start, length ){
//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
function shl( a, b ){
for( ; b--; a = ( ( a %= 0x7fffffff + 1 ) & 0x40000000 ) == 0x40000000 ? a * 2 : ( a - 0x40000000 ) * 2 + 0x7fffffff + 1 );
return a;
}
if( start < 0 || length <= 0 )
return 0;
this.checkBuffer( start + length );
for( var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - ( start >> 3 ) - 1, lastByte = this.buffer.length + ( -( start + length ) >> 3 ), diff = curByte - lastByte, sum = ( ( this.buffer[ curByte ] >> offsetRight ) & ( ( 1 << ( diff ? 8 - offsetRight : length ) ) - 1 ) ) + ( diff && ( offsetLeft = ( start + length ) % 8 ) ? ( this.buffer[ lastByte++ ] & ( ( 1 << offsetLeft ) - 1 ) ) << ( diff-- << 3 ) - offsetRight : 0 ); diff; sum += shl( this.buffer[ lastByte++ ], ( diff-- << 3 ) - offsetRight ) );
return sum;
};
p.warn = function( msg ){
if( this.allowExceptions )
throw new Error( msg );
return 1;
};
p.decodeFloat = function( data, precisionBits, exponentBits ){
var b = new this.Buffer( this.bigEndian, data );
b.checkBuffer( precisionBits + exponentBits + 1 );
//var bias = Math.pow( 2, exponentBits - 1 ) - 1,
var bias = maxBits[exponentBits - 1] - 1,
signal = b.readBits( precisionBits + exponentBits, 1 ), exponent = b.readBits( precisionBits, exponentBits ), significand = 0,
divisor = 2, curByte = b.buffer.length + ( -precisionBits >> 3 ) - 1;
do{
for( var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
}while( precisionBits -= startBit );
var bias = maxBits[exponentBits - 1] - 1
, signal = b.readBits(precisionBits + exponentBits, 1)
, exponent = b.readBits(precisionBits, exponentBits)
, significand = 0
, divisor = 2
, curByte = b.buffer.length + (-precisionBits >> 3) - 1;
do {
for (var byteValue = b.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit; mask >>= 1; ( byteValue & mask ) && ( significand += 1 / divisor ), divisor *= 2 );
} while (precisionBits -= startBit);
return exponent == ( bias << 1 ) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity : ( 1 + signal * -2 ) * ( exponent || significand ? !exponent ? Math.pow( 2, -bias + 1 ) * significand : Math.pow( 2, exponent - bias ) * ( 1 + significand ) : 0 );
};
p.decodeInt = function( data, bits, signed, forceBigEndian ){
var b = new this.Buffer( this.bigEndian||forceBigEndian, data ), x = b.readBits( 0, bits ), max = maxBits[bits]; //max = Math.pow( 2, bits );
return signed && x >= max / 2 ? x - max : x;
BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian) {
var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
, x = b.readBits(0, bits)
, max = maxBits[bits]; //max = Math.pow( 2, bits );
return signed && x >= max / 2
? x - max
: x;
};
p.encodeFloat = function( data, precisionBits, exponentBits ){
//var bias = Math.pow( 2, exponentBits - 1 ) - 1,
var bias = maxBits[exponentBits - 1] - 1,
minExp = -bias + 1, maxExp = bias, minUnnormExp = minExp - precisionBits,
status = isNaN( n = parseFloat( data ) ) || n == -Infinity || n == +Infinity ? n : 0,
exp = 0, len = 2 * bias + 1 + precisionBits + 3, bin = new Array( len ),
signal = ( n = status !== 0 ? 0 : n ) < 0, n = Math.abs( n ), intPart = Math.floor( n ), floatPart = n - intPart,
i, lastBit, rounded, j, result;
for( i = len; i; bin[--i] = 0 );
for( i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor( intPart / 2 ) );
for( i = bias + 1; floatPart > 0 && i; ( bin[++i] = ( ( floatPart *= 2 ) >= 1 ) - 0 ) && --floatPart );
for( i = -1; ++i < len && !bin[i]; );
if( bin[( lastBit = precisionBits - 1 + ( i = ( exp = bias + 1 - i ) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - ( exp = minExp - 1 ) ) ) + 1] ){
if( !( rounded = bin[lastBit] ) ){
for( j = lastBit + 2; !rounded && j < len; rounded = bin[j++] );
BinaryParser.encodeFloat = function encodeFloat (data, precisionBits, exponentBits) {
var bias = maxBits[exponentBits - 1] - 1
, minExp = -bias + 1
, maxExp = bias
, minUnnormExp = minExp - precisionBits
, n = parseFloat(data)
, status = isNaN(n) || n == -Infinity || n == +Infinity ? n : 0
, exp = 0
, len = 2 * bias + 1 + precisionBits + 3
, bin = new Array(len)
, signal = (n = status !== 0 ? 0 : n) < 0
, intPart = Math.floor(n = Math.abs(n))
, floatPart = n - intPart
, lastBit
, rounded
, result
, i
, j;
for (i = len; i; bin[--i] = 0);
for (i = bias + 2; intPart && i; bin[--i] = intPart % 2, intPart = Math.floor(intPart / 2));
for (i = bias + 1; floatPart > 0 && i; (bin[++i] = ((floatPart *= 2) >= 1) - 0 ) && --floatPart);
for (i = -1; ++i < len && !bin[i];);
if (bin[(lastBit = precisionBits - 1 + (i = (exp = bias + 1 - i) >= minExp && exp <= maxExp ? i + 1 : bias + 1 - (exp = minExp - 1))) + 1]) {
if (!(rounded = bin[lastBit])) {
for (j = lastBit + 2; !rounded && j < len; rounded = bin[j++]);
}
for( j = lastBit + 1; rounded && --j >= 0; ( bin[j] = !bin[j] - 0 ) && ( rounded = 0 ) );
for (j = lastBit + 1; rounded && --j >= 0; (bin[j] = !bin[j] - 0) && (rounded = 0));
}
for( i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i]; );
if( ( exp = bias + 1 - i ) >= minExp && exp <= maxExp )
for (i = i - 2 < 0 ? -1 : i - 3; ++i < len && !bin[i];);
if ((exp = bias + 1 - i) >= minExp && exp <= maxExp) {
++i;
else if( exp < minExp ){
exp != bias + 1 - len && exp < minUnnormExp && this.warn( "encodeFloat::float underflow" );
i = bias + 1 - ( exp = minExp - 1 );
} else if (exp < minExp) {
exp != bias + 1 - len && exp < minUnnormExp && this.warn("encodeFloat::float underflow");
i = bias + 1 - (exp = minExp - 1);
}
if( intPart || status !== 0 ){
this.warn( intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status );
if (intPart || status !== 0) {
this.warn(intPart ? "encodeFloat::float overflow" : "encodeFloat::" + status);
exp = maxExp + 1;
i = bias + 2;
if( status == -Infinity )
if (status == -Infinity) {
signal = 1;
else if( isNaN( status ) )
} else if (isNaN(status)) {
bin[i] = 1;
}
}
for( n = Math.abs( exp + bias ), j = exponentBits + 1, result = ""; --j; result = ( n % 2 ) + result, n = n >>= 1 );
for( n = 0, j = 0, i = ( result = ( signal ? "1" : "0" ) + result + bin.slice( i, i + precisionBits ).join( "" ) ).length, r = []; i; j = ( j + 1 ) % 8 ){
n += ( 1 << j ) * result.charAt( --i );
if( j == 7 ){
r[r.length] = String.fromCharCode( n );
for (n = Math.abs(exp + bias), j = exponentBits + 1, result = ""; --j; result = (n % 2) + result, n = n >>= 1);
for (n = 0, j = 0, i = (result = (signal ? "1" : "0") + result + bin.slice(i, i + precisionBits).join("")).length, r = []; i; j = (j + 1) % 8) {
n += (1 << j) * result.charAt(--i);
if (j == 7) {
r[r.length] = String.fromCharCode(n);
n = 0;
}
}
r[r.length] = n ? String.fromCharCode( n ) : "";
return ( this.bigEndian ? r.reverse() : r ).join( "" );
r[r.length] = n
? String.fromCharCode(n)
: "";
return (this.bigEndian ? r.reverse() : r).join("");
};
p.encodeInt = function( data, bits, signed, forceBigEndian ){
//var max = Math.pow( 2, bits );
BinaryParser.encodeInt = function encodeInt (data, bits, signed, forceBigEndian) {
var max = maxBits[bits];
( data >= max || data < -( max / 2 ) ) && this.warn( "encodeInt::overflow" ) && ( data = 0 );
data < 0 && ( data += max );
for( var r = []; data; r[r.length] = String.fromCharCode( data % 256 ), data = Math.floor( data / 256 ) );
for( bits = -( -bits >> 3 ) - r.length; bits--; r[r.length] = "\0" );
return ( (this.bigEndian||forceBigEndian) ? r.reverse() : r ).join( "" );
if (data >= max || data < -(max / 2)) {
this.warn("encodeInt::overflow");
data = 0;
}
if (data < 0) {
data += max;
}
for (var r = []; data; r[r.length] = String.fromCharCode(data % 256), data = Math.floor(data / 256));
for (bits = -(-bits >> 3) - r.length; bits--; r[r.length] = "\0");
return ((this.bigEndian || forceBigEndian) ? r.reverse() : r).join("");
};
p.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
p.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
p.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
p.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
p.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
p.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
p.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
p.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
p.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
p.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
p.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
p.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
p.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
p.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
p.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
p.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
p.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
p.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
p.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
p.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
BinaryParser.toSmall = function( data ){ return this.decodeInt( data, 8, true ); };
BinaryParser.fromSmall = function( data ){ return this.encodeInt( data, 8, true ); };
BinaryParser.toByte = function( data ){ return this.decodeInt( data, 8, false ); };
BinaryParser.fromByte = function( data ){ return this.encodeInt( data, 8, false ); };
BinaryParser.toShort = function( data ){ return this.decodeInt( data, 16, true ); };
BinaryParser.fromShort = function( data ){ return this.encodeInt( data, 16, true ); };
BinaryParser.toWord = function( data ){ return this.decodeInt( data, 16, false ); };
BinaryParser.fromWord = function( data ){ return this.encodeInt( data, 16, false ); };
BinaryParser.toInt = function( data ){ return this.decodeInt( data, 32, true ); };
BinaryParser.fromInt = function( data ){ return this.encodeInt( data, 32, true ); };
BinaryParser.toLong = function( data ){ return this.decodeInt( data, 64, true ); };
BinaryParser.fromLong = function( data ){ return this.encodeInt( data, 64, true ); };
BinaryParser.toDWord = function( data ){ return this.decodeInt( data, 32, false ); };
BinaryParser.fromDWord = function( data ){ return this.encodeInt( data, 32, false ); };
BinaryParser.toQWord = function( data ){ return this.decodeInt( data, 64, true ); };
BinaryParser.fromQWord = function( data ){ return this.encodeInt( data, 64, true ); };
BinaryParser.toFloat = function( data ){ return this.decodeFloat( data, 23, 8 ); };
BinaryParser.fromFloat = function( data ){ return this.encodeFloat( data, 23, 8 ); };
BinaryParser.toDouble = function( data ){ return this.decodeFloat( data, 52, 11 ); };
BinaryParser.fromDouble = function( data ){ return this.encodeFloat( data, 52, 11 ); };
// Factor out the encode so it can be shared by add_header and push_int32
p.encode_int32 = function(number) {
BinaryParser.encode_int32 = function encode_int32 (number) {
var a, b, c, d, unsigned;

@@ -164,3 +191,3 @@ unsigned = (number < 0) ? (number + 0x100000000) : number;

p.encode_int64 = function(number) {
BinaryParser.encode_int64 = function encode_int64 (number) {
var a, b, c, d, e, f, g, h, unsigned;

@@ -187,82 +214,182 @@ unsigned = (number < 0) ? (number + 0x10000000000000000) : number;

/**
UTF8 methods
**/
* UTF8 methods
*/
// Take a raw binary string and return a utf8 string
p.decode_utf8 = function(a) {
var string = "";
var i = 0;
var c, c1, c2, c3;
c = c1 = c2 = 0;
BinaryParser.decode_utf8 = function decode_utf8 (binaryStr) {
var len = binaryStr.length
, decoded = ''
, i = 0
, c = 0
, c1 = 0
, c2 = 0
, c3;
while ( i < a.length ) {
c = a.charCodeAt(i);
while (i < len) {
c = binaryStr.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
decoded += String.fromCharCode(c);
i++;
} else if((c > 191) && (c < 224)) {
c2 = a.charCodeAt(i+1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
} else if ((c > 191) && (c < 224)) {
c2 = binaryStr.charCodeAt(i+1);
decoded += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
} else {
c2 = a.charCodeAt(i+1);
c3 = a.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
c2 = binaryStr.charCodeAt(i+1);
c3 = binaryStr.charCodeAt(i+2);
decoded += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
return decoded;
};
// Encode a cstring correctly
p.encode_cstring = function(s) {
return unescape(encodeURIComponent(s)) + p.fromByte(0);
// Encode a cstring
BinaryParser.encode_cstring = function encode_cstring (s) {
return unescape(encodeURIComponent(s)) + BinaryParser.fromByte(0);
};
// Take a utf8 string and return a binary string
p.encode_utf8 = function(s) {
var a="";
for (var n=0; n< s.length; n++) {
var c=s.charCodeAt(n);
if (c<128) {
BinaryParser.encode_utf8 = function encode_utf8 (s) {
var a = ""
, c;
for (var n = 0, len = s.length; n < len; n++) {
c = s.charCodeAt(n);
if (c < 128) {
a += String.fromCharCode(c);
} else if ((c>127)&&(c<2048)) {
a += String.fromCharCode( (c>>6) | 192) ;
a += String.fromCharCode( (c&63) | 128);
} else if ((c > 127) && (c < 2048)) {
a += String.fromCharCode((c>>6) | 192) ;
a += String.fromCharCode((c&63) | 128);
} else {
a += String.fromCharCode( (c>>12) | 224);
a += String.fromCharCode( ((c>>6) & 63) | 128);
a += String.fromCharCode( (c&63) | 128);
a += String.fromCharCode((c>>12) | 224);
a += String.fromCharCode(((c>>6) & 63) | 128);
a += String.fromCharCode((c&63) | 128);
}
}
return a;
};
p.hprint = function(s) {
for (var i=0; i<s.length; i++) {
if (s.charCodeAt(i)<32) {
var number = s.charCodeAt(i) <= 15 ? "0" + s.charCodeAt(i).toString(16) : s.charCodeAt(i).toString(16);
sys.debug(number+' : ');}
else {
var number = s.charCodeAt(i) <= 15 ? "0" + s.charCodeAt(i).toString(16) : s.charCodeAt(i).toString(16);
sys.debug(number+' : '+ s.charAt(i));}
BinaryParser.hprint = function hprint (s) {
var number;
for (var i = 0, len = s.length; i < len; i++) {
if (s.charCodeAt(i) < 32) {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(16)
: s.charCodeAt(i).toString(16);
process.stdout.write(number)
} else {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(16)
: s.charCodeAt(i).toString(16);
process.stdout.write(number)
}
}
process.stdout.write("\n\n");
};
p.to_byte_array = function(s) {
var array = [];
for (var i=0; i<s.length; i++) {
if (s.charCodeAt(i)<32) {array.push(s.charCodeAt(i));}
else {array.push(s.charCodeAt(i))}
}
sys.puts(array);
}
BinaryParser.ilprint = function hprint (s) {
var number;
p.pprint = function(s) {
for (var i=0; i<s.length; i++) {
if (s.charCodeAt(i)<32) {sys.puts(s.charCodeAt(i)+' : ');}
else {sys.puts(s.charCodeAt(i)+' : '+ s.charAt(i));}
for (var i = 0, len = s.length; i < len; i++) {
if (s.charCodeAt(i) < 32) {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(10)
: s.charCodeAt(i).toString(10);
sys.debug(number+' : ');
} else {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(10)
: s.charCodeAt(i).toString(10);
sys.debug(number+' : '+ s.charAt(i));
}
}
};
BinaryParser.hlprint = function hprint (s) {
var number;
for (var i = 0, len = s.length; i < len; i++) {
if (s.charCodeAt(i) < 32) {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(16)
: s.charCodeAt(i).toString(16);
sys.debug(number+' : ');
} else {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(16)
: s.charCodeAt(i).toString(16);
sys.debug(number+' : '+ s.charAt(i));
}
}
};
/**
* BinaryParser buffer constructor.
*/
function BinaryParserBuffer (bigEndian, buffer) {
this.bigEndian = bigEndian || 0;
this.buffer = [];
this.setBuffer(buffer);
};
BinaryParserBuffer.prototype.setBuffer = function setBuffer (data) {
var l, i, b;
if (data) {
i = l = data.length;
b = this.buffer = new Array(l);
for (; i; b[l - i] = data.charCodeAt(--i));
this.bigEndian && b.reverse();
}
};
BinaryParserBuffer.prototype.hasNeededBits = function hasNeededBits (neededBits) {
return this.buffer.length >= -(-neededBits >> 3);
};
BinaryParserBuffer.prototype.checkBuffer = function checkBuffer (neededBits) {
if (!this.hasNeededBits(neededBits)) {
throw new Error("checkBuffer::missing bytes");
}
};
BinaryParserBuffer.prototype.readBits = function readBits (start, length) {
//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
function shl (a, b) {
for (; b--; a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1);
return a;
}
if (start < 0 || length <= 0) {
return 0;
}
this.checkBuffer(start + length);
var offsetLeft
, offsetRight = start % 8
, curByte = this.buffer.length - ( start >> 3 ) - 1
, lastByte = this.buffer.length + ( -( start + length ) >> 3 )
, diff = curByte - lastByte
, sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1)) + (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[lastByte++] & ((1 << offsetLeft) - 1)) << (diff-- << 3) - offsetRight : 0);
for(; diff; sum += shl(this.buffer[lastByte++], (diff-- << 3) - offsetRight));
return sum;
};
/**
* Expose.
*/
exports.BinaryParser = BinaryParser;
BinaryParser.Buffer = BinaryParserBuffer;

@@ -1,16 +0,18 @@

var BinaryParser = require('./binary_parser').BinaryParser,
Integer = require('../goog/math/integer').Integer,
Long = require('../goog/math/long').Long,
Buffer = require('buffer').Buffer;
// Alias a string function
var chr = String.fromCharCode;
/**
* Module dependencies.
*/
var BinaryParser = require('./binary_parser').BinaryParser
, Long = require('../goog/math/long').Long
, Timestamp = require('./timestamp').Timestamp
, ObjectID = require('./objectid').ObjectID
, Binary = require('./binary').Binary
, debug = require('util').debug
, inspect = require('util').inspect
, inherits = require('util').inherits;
var BSON = exports.BSON = function(){},
sys = require('sys');
/**
* BSON constructor.
*/
// Exports Long value
exports.Long = Long;
exports.Timestamp = Long;
var Timestamp = Long
function BSON () {};

@@ -38,2 +40,3 @@ // BSON MAX VALUES

// BSON BINARY DATA SUBTYPES
BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;

@@ -45,279 +48,482 @@ BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;

BSON.serialize = function(data, checkKeys) {
/**
* Serialize `data` as BSON.
*
* @param {TODO} data
* @param {Bool|null} checkKeys - TODO
* @return {TODO}
*/
BSON.serialize = function serialize (data, checkKeys) {
return BSON.encodeValue('', null, data, true, checkKeys == null ? false : checkKeys);
};
BSON.deserialize = function(data, is_array_item, returnData, returnArray) {
/**
* Deserialize `data` as BSON.
*
* @param {TODO} data
* @param {Bool} is_array_item
* @param {TODO} returnData
* @param {TODO} returnArray
* @return {TODO}
*/
BSON.deserialize = function deserialize (data, is_array_item, returnData, returnArray) {
// The return data
var return_data = {};
var return_array = [];
// Index of decoding in the binary file
var index = 0;
// Split of the first 4 characters to get the number of bytes
var size = BinaryParser.toInt(data.substr(0, 4));
// Adjust index
index = index + 4;
while(index < data.length) {
// Read the first byte indicating the type of object
var type = BinaryParser.toSmall(data.substr(index, 1));
var insert_index = 0;
// Adjust for the type of element
index = index + 1;
// If it's a string decode the value
if(type == BSON.BSON_DATA_STRING) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the length of the string (next 4 bytes)
var string_size = BinaryParser.toInt(data.substr(index, 4));
// Adjust the index to point at start of string
index = index + 4;
// Read the string
var value = BinaryParser.decode_utf8(data.substr(index, string_size - 1));
// Adjust the index with the size of the string
index = index + string_size;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_NULL) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Set the data on the object
is_array_item ? return_array[insert_index] = null : return_data[string_name] = null;
} else if(type == BSON.BSON_DATA_INT) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the number value
var value = BinaryParser.toInt(data.substr(index, 4));
// Adjust the index with the size
index = index + 4;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_LONG || type == BSON.BSON_DATA_TIMESTAMP) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the number value
var low_bits = Integer.fromInt(BinaryParser.toInt(data.substr(index, 4)));
var high_bits = Integer.fromInt(BinaryParser.toInt(data.substr(index + 4, 4)));
// Create to integers
var value = type == BSON.BSON_DATA_TIMESTAMP ? new Timestamp(low_bits, high_bits) : new Long(low_bits, high_bits);
// Adjust the index with the size
index = index + 8;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_NUMBER) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the number value
var value = BinaryParser.toDouble(data.substr(index, 8));
// Adjust the index with the size
index = index + 8;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_OBJECT) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the size of the object
var object_size = BinaryParser.toInt(data.substr(index, 4));
// Do a substr based on the size and parse the sub object
var object_data = data.substr(index, object_size);
// Parse the object
var value = BSON.deserialize(object_data, false);
// Adjust the index for the next value
index = index + object_size;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_ARRAY) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the size of the object
var array_size = BinaryParser.toInt(data.substr(index, 4));
// Let's split off the data and parse all elements (keeping in mind the elements)
var array_data = data.substr(index, array_size);
// Parse the object
var value = BSON.deserialize(array_data, true);
// Adjust the index for the next value
index = index + array_size;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_BOOLEAN) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the length of the string (next 4 bytes)
var boolean_value = BinaryParser.toSmall(data.substr(index, 1));
var value = boolean_value == 1 ? true : false;
// Adjust the index
index = index + 1;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_DATE) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the number value
var low_bits = Integer.fromInt(BinaryParser.toInt(data.substr(index, 4)));
var high_bits = Integer.fromInt(BinaryParser.toInt(data.substr(index + 4, 4)));
// Create to integers
var value_in_seconds = new Long(low_bits, high_bits).toNumber();
// Calculate date with miliseconds
var value = new Date();
value.setTime(value_in_seconds);
// Adjust the index
index = index + 8;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_OID) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read the oid (12 bytes)
var oid = data.substr(index, 12);
// Calculate date with miliseconds
var value = new exports.ObjectID(oid);
// Adjust the index
index = index + 12;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_CODE_W_SCOPE) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Unpack the integer sizes
var total_code_size = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
var string_size = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
// Read the string + terminating null
var code_string = BinaryParser.decode_utf8(data.substr(index, string_size - 1));
index = index + string_size;
// Get the bson object
var bson_object_size = total_code_size - string_size - 8;
var bson_object_string = data.substr(index, bson_object_size);
index = index + bson_object_size;
// Parse the bson object
var scope_object = BSON.deserialize(bson_object_string, false);
// Create code object
var value = new exports.Code(code_string, scope_object);
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_REGEXP) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// Read characters until end of regular expression
var reg_exp_array = [];
var chr = 1;
var start_index = index
while(BinaryParser.toByte((chr = data.charAt(index))) != 0) {
index = index + 1
}
// RegExp Expression
reg_exp = data.substring(start_index, index)
index = index + 1
// Read the options for the regular expression
var options_array = [];
while(BinaryParser.toByte((chr = data.charAt(index++))) != 0) {
options_array.push(chr);
}
// Regular expression
var value = new RegExp(BinaryParser.decode_utf8(reg_exp), options_array.join(''));
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
} else if(type == BSON.BSON_DATA_BINARY) {
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// If we have an index read the array index
if(is_array_item) insert_index = parseInt(string_name, 10);
// The total number of bytes after subtype
var total_number_of_bytes = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
// Decode the subtype
var sub_type = BinaryParser.toByte(data.substr(index, 1));
index = index + 1;
// Binary object
var value = new exports.Binary();
value.sub_type = sub_type;
// Read the size of the binary
var number_of_bytes = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
// Read the next bytes into our Binary object
var bin_data = data.substr(index, number_of_bytes);
value.write(bin_data);
// Adjust index with number of bytes
index = index + number_of_bytes;
// Set the data on the object
is_array_item ? return_array[insert_index] = value : return_data[string_name] = value;
switch (type) {
case BSON.BSON_DATA_STRING:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
string_name = BinaryParser.decode_utf8(string_name);
//
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the length of the string (next 4 bytes)
var string_size = BinaryParser.toInt(data.substr(index, 4));
// Adjust the index to point at start of string
index = index + 4;
// Read the string
var value = BinaryParser.decode_utf8(data.substr(index, string_size - 1));
// Adjust the index with the size of the string
index = index + string_size;
// Set the data on the object
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_NULL:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Set the data on the object
if (is_array_item) {
return_array[parseInt(string_name, 10)] = null;
} else {
return_data[string_name] = null;
}
break;
case BSON.BSON_DATA_INT:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the number value
var value = BinaryParser.toInt(data.substr(index, 4));
// Adjust the index with the size
index = index + 4;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_LONG:
case BSON.BSON_DATA_TIMESTAMP:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the number value
var low_bits = BinaryParser.toInt(data.substr(index, 4));
var high_bits = BinaryParser.toInt(data.substr(index + 4, 4));
var value = new Long(low_bits, high_bits);
// Adjust the index with the size
index = index + 8;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_NUMBER:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the number value
var value = BinaryParser.toDouble(data.substr(index, 8));
// Adjust the index with the size
index = index + 8;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_OBJECT:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the size of the object
var object_size = BinaryParser.toInt(data.substr(index, 4));
// Do a substr based on the size and parse the sub object
var object_data = data.substr(index, object_size);
// Parse the object
var value = BSON.deserialize(object_data, false);
// Adjust the index for the next value
index = index + object_size;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_ARRAY:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the size of the object
var array_size = BinaryParser.toInt(data.substr(index, 4));
// Let's split off the data and parse all elements (keeping in mind the elements)
var array_data = data.substr(index, array_size);
// Parse the object
var value = BSON.deserialize(array_data, true);
// Adjust the index for the next value
index = index + array_size;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_BOOLEAN:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the length of the string (next 4 bytes)
var boolean_value = BinaryParser.toSmall(data.substr(index, 1));
var value = 1 === boolean_value;
// Adjust the index
index = index + 1;
// Set the data on the object
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_DATE:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the number value
var low_bits = BinaryParser.toInt(data.substr(index, 4));
var high_bits = BinaryParser.toInt(data.substr(index + 4, 4));
// Create to integers
var value_in_seconds = new Long(low_bits, high_bits).toNumber();
// Calculate date with miliseconds
var value = new Date();
value.setTime(value_in_seconds);
// Adjust the index
index = index + 8;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_OID:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the oid (12 bytes)
var oid = data.substr(index, 12);
// Calculate date with miliseconds
var value = new ObjectID(oid);
// Adjust the index
index = index + 12;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_CODE_W_SCOPE:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Unpack the integer sizes
var total_code_size = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
var string_size = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
// Read the string + terminating null
var code_string = BinaryParser.decode_utf8(data.substr(index, string_size - 1));
index = index + string_size;
// Get the bson object
var bson_object_size = total_code_size - string_size - 8;
var bson_object_string = data.substr(index, bson_object_size);
index = index + bson_object_size;
// Parse the bson object
var scope_object = BSON.deserialize(bson_object_string, false);
// Create code object
var value = new exports.Code(code_string, scope_object);
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_REGEXP:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
// string_name = decodeURIComponent(escape(string_name));
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read characters until end of regular expression
var reg_exp_array = [];
var chr = 1;
var start_index = index;
while(BinaryParser.toByte((chr = data.charAt(index))) != 0) {
++index;
}
// RegExp Expression
reg_exp = data.substring(start_index, index);
index = index + 1;
// Read the options for the regular expression
var options_array = [];
while(BinaryParser.toByte((chr = data.charAt(index++))) != 0) {
options_array.push(chr);
}
// Regular expression
var value = new RegExp(BinaryParser.decode_utf8(reg_exp), options_array.join(''));
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
case BSON.BSON_DATA_BINARY:
// Read the null terminated string (indexof until first 0)
var string_end_index = data.indexOf('\0', index);
var string_name = data.substring(index, string_end_index);
// UTF-8 decode key name
string_name = BinaryParser.decode_utf8(string_name);
// Ajust index to point to the end of the string
index = string_end_index + 1;
// Read the size of the binary
var number_of_bytes = BinaryParser.toInt(data.substr(index, 4));
index = index + 4;
// Decode the subtype
var sub_type = BinaryParser.toByte(data.substr(index, 1));
index = index + 1;
// Binary object
var value = new Binary();
value.sub_type = sub_type;
// Read the next bytes into our Binary object
var bin_data = data.substr(index, number_of_bytes);
value.write(bin_data);
// Adjust index with number of bytes
index = index + number_of_bytes;
if (is_array_item) {
return_array[parseInt(string_name, 10)] = value;
} else {
return_data[string_name] = value;
}
break;
}
}
// Check if we have a db reference
if(!is_array_item && return_data['$ref'] != null) {
return_data = new exports.DBRef(return_data['$ref'], return_data['$id'], return_data['$db']);
if(!is_array_item && null != return_data['$ref']) {
return_data = new exports.DBRef( return_data['$ref']
, return_data['$id']
, return_data['$db']);
}
// Return the data
return is_array_item ? return_array : return_data;
return is_array_item
? return_array
: return_data;
};
BSON.encodeString = function(string) {
/**
* Encode a string as BSON.
*
* @param {TODO} string
* @return {TODO}
*/
BSON.encodeString = function encodeString (string) {
var encodedString = BinaryParser.encode_cstring(string);

@@ -328,18 +534,50 @@ // Encode the string as binary with the length

BSON.encodeInt = function(number) {
return BinaryParser.fromInt(number.toInt());
/**
* Encode an Int as BSON.
*
* @param {TODO} number
* @return {TODO}
*/
BSON.encodeInt = function encodeInt (number) {
return BinaryParser.fromInt(number);
};
BSON.encodeLong = function(number) {
return BinaryParser.fromInt(number.getLowBits()) + BinaryParser.fromInt(number.getHighBits());
/**
* Encode a Long as BSON.
*
* @param {TODO} number
* @return {TODO}
*/
BSON.encodeLong = function encodeLong (number) {
return BinaryParser.fromInt(number.getLowBits())
+ BinaryParser.fromInt(number.getHighBits());
};
BSON.encodeFloat = function(number) {
/**
* Encode a Float as BSON.
*
* @param {TODO} number
* @return {TODO}
*/
BSON.encodeFloat = function encodeFloat (number) {
return BinaryParser.fromDouble(number);
};
BSON.encodeArray = function(array, checkKeys) {
/**
* Encode an array as BSON.
*
* @param {TODO} array
* @param {Bool} checkKeys - TODO
* @return {TODO}
*/
BSON.encodeArray = function encodeArray (array, checkKeys) {
var encoded_string = '';
var index = 0;
var len = array.length;
for(var index = 0; index < array.length; index++) {
for(; index < len; ++index) {
var index_string = new String(index) + BinaryParser.fromByte(0);

@@ -353,130 +591,290 @@ var encoded_object = BSON.encodeValue('', null, array[index], false, checkKeys);

BSON.encodeObject = function(object, checkKeys) {
/**
* Encode an object as BSON.
*
* @param {TODO} object
* @param {Bool} checkKeys - TODO
* @return {TODO}
*/
BSON.encodeObject = function encodeObject (object, checkKeys) {
var encoded_string = '';
// Let's fetch all the variables for the object and encode each
for(var variable in object) {
if(object[variable] == null || (object[variable] != null && object[variable].constructor != Function)) {
encoded_string += BSON.encodeValue('', variable, object[variable], false, checkKeys);
var keys = Object.keys(object);
var len = keys.length;
var key, val;
for (var i = 0; i < len; ++i) {
key = keys[i];
val = object[key];
if(null == val || (val != null && val.constructor != Function)) {
encoded_string += BSON.encodeValue('', key, val, false, checkKeys);
}
}
// Return the encoded string
return encoded_string;
};
BSON.encodeBoolean = function(value) {
return value ? BinaryParser.fromSmall(1) : BinaryParser.fromSmall(0);
/**
* Encode a boolean as BSON.
*
* @param {TODO} bool
* @return {TODO}
*/
BSON.encodeBoolean = function encodeBoolean (bool) {
return BinaryParser.fromSmall(bool ? 1 : 0);
};
BSON.encodeDate = function(value) {
var dateInMilis = Long.fromNumber(value.getTime());
return BinaryParser.fromInt(dateInMilis.getLowBits()) + BinaryParser.fromInt(dateInMilis.getHighBits());
/**
* Encode a date as BSON.
*
* @param {TODO} date
* @return {TODO}
*/
BSON.encodeDate = function encodeDate (date) {
var dateInMilis = Long.fromNumber(date.getTime());
return BinaryParser.fromInt(dateInMilis.getLowBits())
+ BinaryParser.fromInt(dateInMilis.getHighBits());
};
BSON.encodeOid = function(oid) {
/**
* Encode a ObjectId as BSON.
*
* @param {ObjectId} oid
* @return {TODO}
*/
BSON.encodeOid = function encodeOid (oid) {
return oid.id;
};
BSON.encodeCode = function(code, checkKeys) {
// Get the code_string
/**
* Encode a CodeString as BSON.
*
* @param {TODO} code
* @param {Bools} checkKeys
* @return {TODO}
*/
BSON.encodeCode = function encodeCode (code, checkKeys) {
var code_string = BSON.encodeString(code.code);
var scope = BinaryParser.fromInt(5) + BinaryParser.fromByte(0);
// Encode the scope (a hash of values or ordered hash)
if(code.scope != null) {
if(null != code.scope) {
scope = BSON.encodeValue('', null, code.scope, false, checkKeys);
scope = scope.substring(1, scope.length);
}
// Calculate lengths
var total_length = code_string.length - 4 + scope.length + 8;
return BinaryParser.fromInt(total_length) + code_string + scope;
};
BSON.encodeRegExp = function(regexp) {
// Get regular expression
var clean_regexp = regexp.toString().match(/\/.*\//, '');
/**
* Encode a RegExp as BSON.
*
* @param {RegExp} regexp
* @return {TODO}
*/
BSON.encodeRegExp = function encodeRegExp (regexp) {
var options_array = [];
var str = regexp.toString();
var clean_regexp = str.match(/\/.*\//, '');
clean_regexp = clean_regexp[0].substring(1, clean_regexp[0].length - 1);
var options = regexp.toString().substr(clean_regexp.length + 2);
var options_array = [];
var options = str.substr(clean_regexp.length + 2);
// Extract all options that are legal and sort them alphabetically
for(var index = 0; index < options.length; index++) {
for(var index = 0, len = options.length; index < len; ++index) {
var chr = options.charAt(index);
if(chr == 'i' || chr == 'm' || chr == 'x') options_array.push(chr);
if('i' == chr || 'm' == chr || 'x' == chr) {
options_array.push(chr);
}
}
// Don't need to sort the alphabetically as it's already done by javascript on creation of a Regexp obejct
options = options_array.join('');
// Encode the regular expression
return BinaryParser.encode_cstring(clean_regexp) + BinaryParser.encode_cstring(options);
return BinaryParser.encode_cstring(clean_regexp)
+ BinaryParser.encode_cstring(options);
};
BSON.encodeBinary = function(binary) {
/**
* Encode a binary as BSON.
*
* @param {TODO} binary
* @return {TODO}
*/
BSON.encodeBinary = function encodeBinary (binary) {
var data = binary.value();
return BinaryParser.fromByte(binary.sub_type) + BinaryParser.fromInt(data.length) + data;
return BinaryParser.fromInt(data.length) + BinaryParser.fromByte(binary.sub_type) + data;
};
BSON.encodeDBRef = function(dbref) {
var ordered_values = {'$ref':dbref.namespace, '$id':dbref.oid};
if(dbref.db != null) ordered_values['$db'] = dbref.db;
/**
* Encode a DBRef as BSON.
*
* @param {TODO} dbref
* @return {TODO}
*/
BSON.encodeDBRef = function encodeDBRef (dbref) {
var ordered_values = {
'$ref': dbref.namespace
, '$id' : dbref.oid
};
if(null != dbref.db) {
ordered_values['$db'] = dbref.db;
}
return BSON.encodeObject(ordered_values);
};
BSON.checkKey = function(variable) {
/**
* Check if key name is valid.
*
* @param {TODO} key
*/
BSON.checkKey = function checkKey (key) {
if (!key.length) return;
// Check if we have a legal key for the object
if(variable.length > 0 && variable.substr(0, 1) == '$') {
throw Error("key " + variable + " must not start with '$'");
} else if(variable.length > 0 && variable.indexOf('.') != -1) {
throw Error("key " + variable + " must not contain '.'");
if ('$' == key[0]) {
throw Error("key " + key + " must not start with '$'");
} else if (!!~key.indexOf('.')) {
throw Error("key " + key + " must not contain '.'");
}
};
BSON.toLong = function(low_bits, high_bits) {
var low_bits = Integer.fromInt(low_bits);
var high_bits = Integer.fromInt(high_bits);
/**
* Convert bits to Long.
*
* @param {int} low_bits
* @param {int} high_bits
* @return {Long}
*/
BSON.toLong = function toLong (low_bits, high_bits) {
// var low_bits = Integer.fromInt(low_bits);
// var high_bits = Integer.fromInt(high_bits);
return new Long(low_bits, high_bits);
}
};
BSON.toInt = function(value) {
return Integer.fromNumber(value).toInt();
}
/**
* Converts value to an Integer.
*
* @param {value}
* @return {Integer}
*/
BSON.encodeValue = function(encoded_string, variable, value, top_level, checkKeys) {
var variable_encoded = variable == null ? '' : BinaryParser.encode_cstring(variable);
if(checkKeys && variable != null)BSON.checkKey(variable);
BSON.toInt = function toInt (value) {
return Math.floor(value);
};
/**
* Encodes value as BSON.
*
* @param {TODO} encoded_string
* @param {TODO} variable
* @param {TODO} value
* @param {TODO} top_level
* @param {TODO} checkKeys
* @return {String}
*/
BSON.encodeValue = function encodeValue (encoded_string, variable, value, top_level, checkKeys) {
var toString = Object.prototype.toString;
var variable_encoded = variable == null
? ''
: BinaryParser.encode_cstring(variable);
if(checkKeys && variable != null) {
BSON.checkKey(variable);
}
if(value == null) {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_NULL) + variable_encoded;
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_NULL)
+ variable_encoded;
} else if(value.constructor == String) {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_STRING) + variable_encoded + BSON.encodeString(value);
} else if(value instanceof Timestamp || Object.prototype.toString.call(value) == "[object Timestamp]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_TIMESTAMP) + variable_encoded + BSON.encodeLong(value);
} else if(value instanceof Long || Object.prototype.toString.call(value) == "[object Long]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_LONG) + variable_encoded + BSON.encodeLong(value);
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_STRING)
+ variable_encoded
+ BSON.encodeString(value);
} else if(value instanceof Timestamp || toString.call(value) == "[object Timestamp]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_TIMESTAMP)
+ variable_encoded
+ BSON.encodeLong(value);
} else if(value instanceof Long || toString.call(value) == "[object Long]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_LONG)
+ variable_encoded
+ BSON.encodeLong(value);
} else if(value.constructor == Number && value === parseInt(value, 10)) {
if(value > BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN) {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_LONG) + variable_encoded + BSON.encodeLong(Long.fromNumber(value));
if(value > BSON.BSON_INT32_MAX || value < BSON.BSON_INT32_MIN) {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_LONG)
+ variable_encoded
+ BSON.encodeLong(Long.fromNumber(value));
} else {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_INT) + variable_encoded + BSON.encodeInt(Integer.fromInt(value));
}
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_INT)
+ variable_encoded
+ BSON.encodeInt(value);
}
} else if(value.constructor == Number) {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_NUMBER) + variable_encoded + BSON.encodeFloat(value);
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_NUMBER)
+ variable_encoded
+ BSON.encodeFloat(value);
} else if(Array.isArray(value)) {
var object_string = BSON.encodeArray(value, checkKeys);
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_ARRAY) + variable_encoded + BSON.encodeInt(Integer.fromInt(object_string.length + 4 + 1)) + object_string + BinaryParser.fromByte(0);
} else if(Object.prototype.toString.call(value) === '[object Boolean]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_BOOLEAN) + variable_encoded + BSON.encodeBoolean(value);
} else if(Object.prototype.toString.call(value) === '[object Date]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_DATE) + variable_encoded + BSON.encodeDate(value);
} else if(Object.prototype.toString.call(value) === '[object RegExp]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_REGEXP) + variable_encoded + BSON.encodeRegExp(value);
} else if(value instanceof ObjectID || (value.id && value.toHexString) || Object.prototype.toString.call(value) == "[object ObjectID]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_OID) + variable_encoded + BSON.encodeOid(value);
} else if(value instanceof Code || Object.prototype.toString.call(value) == "[object Code]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_CODE_W_SCOPE) + variable_encoded + BSON.encodeCode(value, checkKeys);
} else if(value instanceof Binary || Object.prototype.toString.call(value) == "[object Binary]") {
var object_string = BSON.encodeBinary(value);
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_BINARY) + variable_encoded + BSON.encodeInt(Integer.fromInt(object_string.length - 1)) + object_string;
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_ARRAY)
+ variable_encoded
+ BSON.encodeInt(object_string.length + 4 + 1)
+ object_string
+ BinaryParser.fromByte(0);
} else if(toString.call(value) === '[object Boolean]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_BOOLEAN)
+ variable_encoded
+ BSON.encodeBoolean(value);
} else if(toString.call(value) === '[object Date]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_DATE)
+ variable_encoded
+ BSON.encodeDate(value);
} else if(toString.call(value) === '[object RegExp]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_REGEXP)
+ variable_encoded
+ BSON.encodeRegExp(value);
} else if(value instanceof ObjectID ||
(value.id && value.toHexString) ||
toString.call(value) === '[object ObjectID]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_OID)
+ variable_encoded
+ BSON.encodeOid(value);
} else if(value instanceof Code || toString.call(value) == "[object Code]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_CODE_W_SCOPE)
+ variable_encoded
+ BSON.encodeCode(value, checkKeys);
} else if(value instanceof Binary || toString.call(value) == "[object Binary]") {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_BINARY)
+ variable_encoded
+ BSON.encodeBinary(value);
} else if(value instanceof DBRef) {
var object_string = BSON.encodeDBRef(value);
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_OBJECT) + variable_encoded + BSON.encodeInt(Integer.fromInt(object_string.length + 4 + 1)) + object_string + BinaryParser.fromByte(0);
} else if(Object.prototype.toString.call(value) === '[object Object]') {
encoded_string += BinaryParser.fromByte(BSON.BSON_DATA_OBJECT)
+ variable_encoded
+ BSON.encodeInt(object_string.length + 4 + 1)
+ object_string
+ BinaryParser.fromByte(0);
} else if(toString.call(value) === '[object Object]') {
var object_string = BSON.encodeObject(value, checkKeys);
encoded_string += (!top_level ? BinaryParser.fromByte(BSON.BSON_DATA_OBJECT) : '') + variable_encoded + BSON.encodeInt(Integer.fromInt(object_string.length + 4 + 1)) + object_string + BinaryParser.fromByte(0);
encoded_string += (!top_level ? BinaryParser.fromByte(BSON.BSON_DATA_OBJECT) : '')
+ variable_encoded
+ BSON.encodeInt(object_string.length + 4 + 1)
+ object_string
+ BinaryParser.fromByte(0);
}

@@ -487,3 +885,10 @@

var Code = exports.Code = function(code, scope) {
/**
* Code constructor.
*
* @param {TODO} code
* @param {TODO} scope
*/
function Code (code, scope) {
this.code = code;

@@ -494,85 +899,10 @@ this.scope = scope == null ? {} : scope;

/**
Object ID used to create object id's for the mongo requests
**/
var ObjectID = exports.ObjectID = function(id) {
if(id == null) this.id = this.generate();
else if( /^[0-9a-fA-F]{24}$/.test(id)) return ObjectID.createFromHexString(id);
else this.id = id;
};
* DBRef constructor.
*
* @param {TODO} namespace
* @param {TODO} oid
* @param {TODO} db
*/
ObjectID.prototype.get_inc = function() {
exports.ObjectID.index = (exports.ObjectID.index + 1) % 0xFFFFFF;
return exports.ObjectID.index;
};
/* Find the machine id. */
var MACHINE_ID = (function() {
// Create a random 3-byte value (i.e. unique for this
// process). Other drivers use a md5 of the machine id here, but
// that would mean an asyc call to gethostname, so we don't bother.
var rnd = parseInt(Math.random() * 0xffffff);
return rnd;
})();
ObjectID.prototype.generate = function() {
var unixTime = parseInt((new Date()).getTime()/1000);
var time4Bytes = BinaryParser.encodeInt(unixTime, 32, true, true);
var machine3Bytes = BinaryParser.encodeInt(MACHINE_ID, 24, false);
var pid2Bytes = BinaryParser.fromShort(process.pid);
var index3Bytes = BinaryParser.encodeInt(this.get_inc(), 24, false, true);
return time4Bytes + machine3Bytes + pid2Bytes + index3Bytes;
};
ObjectID.prototype.toHexString = function() {
var hexString = '';
for(var index = 0; index < this.id.length; index++) {
var value = BinaryParser.toByte(this.id.substr(index, 1));
var number = value <= 15 ? "0" + value.toString(16) : value.toString(16);
hexString = hexString + number;
}
return hexString;
};
ObjectID.prototype.toString = function() {
return this.toHexString();
};
ObjectID.prototype.inspect = function() {
return this.toHexString();
}
// accurate up to number of seconds
ObjectID.prototype.__defineGetter__("generationTime", function() {
return BinaryParser.decodeInt(this.id.substring(0,4), 32, true, true) * 1000;
})
ObjectID.index = 0;
ObjectID.createPk = function() {
return new exports.ObjectID();
};
ObjectID.createFromHexString= function(hexString) {
if(hexString.length > 12*2) throw "Id cannot be longer than 12 bytes";
var result= "";
for(var index=0 ; index < hexString.length; index+=2) {
var string= hexString.substr(index, 2);
var number= parseInt(string, 16);
result+= BinaryParser.fromByte(number);
}
return new exports.ObjectID(result);
};
ObjectID.prototype.toJSON = function() {
return this.toHexString();
}
ObjectID.prototype.equals = function(otherID) {
return this.id == ((otherID instanceof ObjectID || otherID.toHexString) ? otherID.id : ObjectID.createFromHexString(otherID).id);
}
/**
DBRef contains a db reference
**/
var DBRef = exports.DBRef = function(namespace, oid, db) {
function DBRef (namespace, oid, db) {
this.namespace = namespace;

@@ -583,63 +913,20 @@ this.oid = oid;

DBRef.prototype.toJSON = function() {
return JSON.stringify({
'$ref':this.namespace,
'$id':this.oid,
'$db':this.db == null ? '' : this.db
});
}
/**
Contains the a binary stream of data
**/
var Binary = exports.Binary = function(buffer) {
this.sub_type = BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY;
// Create a default sized binary in case non is passed in and prepare the size
if(buffer) {
this.buffer = buffer;
this.position = buffer.length;
} else {
this.buffer = new Buffer(Binary.BUFFER_SIZE);
this.position = 0;
}
};
* Expose.
*/
Binary.BUFFER_SIZE = 256;
Binary.prototype.put = function(byte_value) {
if(this.buffer.length > this.position) {
this.buffer[this.position++] = byte_value.charCodeAt(0);
} else {
// Create additional overflow buffer
var buffer = new Buffer(Binary.BUFFER_SIZE + this.buffer.length);
// Combine the two buffers together
this.buffer.copy(buffer, 0, 0, this.buffer.length);
this.buffer = buffer;
this.buffer[this.position++] = byte_value.charCodeAt(0);
}
};
Binary.prototype.write = function(string, offset) {
offset = offset ? offset : this.position;
// If the buffer is to small let's extend the buffer
if(this.buffer.length < offset + string.length) {
var buffer = new Buffer(this.buffer.length + string.length);
this.buffer.copy(buffer, 0, 0, this.buffer.length);
// Assign the new buffer
this.buffer = buffer;
}
// Write the content to the buffer
if(string instanceof Buffer) {
string.copy(this.buffer, offset, 0, string.length);
}
else {
this.buffer.write(string, 'binary', offset);
}
this.position = offset + string.length;
};
Binary.prototype.read = function(position, length) {
length = length && length > 0 ? length : this.position;
// Let's extract the string we want to read
return this.buffer.toString('binary', position, position + length);
};
Binary.prototype.value = function() {
return this.buffer.toString('binary', 0, this.position);
};
Binary.prototype.length = function() {
return this.position;
};
exports.Code = Code;
exports.BSON = BSON;
exports.DBRef = DBRef;
exports.Binary = Binary;
exports.ObjectID = ObjectID;
exports.Long = Long;
exports.Timestamp = Timestamp;

@@ -1,28 +0,43 @@

var InsertCommand = require('./commands/insert_command').InsertCommand,
QueryCommand = require('./commands/query_command').QueryCommand,
DeleteCommand = require('./commands/delete_command').DeleteCommand,
UpdateCommand = require('./commands/update_command').UpdateCommand,
DbCommand = require('./commands/db_command').DbCommand,
BinaryParser = require('./bson/binary_parser').BinaryParser,
Cursor = require('./cursor').Cursor;
/**
* Module dependencies.
*/
var InsertCommand = require('./commands/insert_command').InsertCommand
, QueryCommand = require('./commands/query_command').QueryCommand
, DeleteCommand = require('./commands/delete_command').DeleteCommand
, UpdateCommand = require('./commands/update_command').UpdateCommand
, DbCommand = require('./commands/db_command').DbCommand
, BinaryParser = require('./bson/binary_parser').BinaryParser
, Cursor = require('./cursor').Cursor
, debug = require('util').debug
, inspect = require('util').inspect;
/**
* Sort functions, Normalize and prepare sort parameters
*/
/**
Sort functions, Normalize and prepare sort parameters
**/
var formatSortValue = function(sortDirection) {
function formatSortValue (sortDirection) {
var value = ("" + sortDirection).toLowerCase();
if(value == 'ascending' || value == 'asc' || value == 1) return 1;
if(value == 'descending' || value == 'desc' || value == -1 ) return -1;
throw new Error("Illegal sort clause, must be of the form " +
"[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]");
switch (value) {
case 'ascending':
case 'asc':
case '1':
return 1;
case 'descending':
case 'desc':
case '-1':
return -1;
default:
throw new Error("Illegal sort clause, must be of the form "
+ "[['field1', '(ascending|descending)'], "
+ "['field2', '(ascending|descending)']]");
}
};
var formattedOrderClause = function(sortValue) {
function formattedOrderClause (sortValue) {
var orderBy = {};
var self = this;
if(Array.isArray(sortValue)) {
sortValue.forEach(function(sortElement) {
if(sortElement.constructor == String) {
if (Array.isArray(sortValue)) {
sortValue.forEach(function (sortElement) {
if (sortElement.constructor == String) {
orderBy[sortElement] = 1;

@@ -33,3 +48,3 @@ } else {

});
} else if(sortValue.constructor == String) {
} else if (sortValue.constructor == String) {
orderBy[sortValue] = 1;

@@ -40,2 +55,3 @@ } else {

}
return orderBy;

@@ -45,158 +61,255 @@ };

/**
Handles all the operations on objects in collections
**/
var Collection = exports.Collection = function(db, collectionName, pkFactory) {
* toString helper.
*/
var toString = Object.prototype.toString;
/**
* Collection constructor.
*
* @param {Database} db
* @param {String} collectionName
* @param {Function} pkFactory
*/
function Collection (db, collectionName, pkFactory, options) {
this.checkCollectionName(collectionName);
this.db = db;
this.collectionName = collectionName;
this.internalHint;
this.pkFactory = pkFactory == null ? db.bson_serializer.ObjectID : pkFactory;
// Add getter and setters
this.__defineGetter__("hint", function() { return this.internalHint; });
this.__defineSetter__("hint", function(value) { this.internalHint = this.normalizeHintField(value); });
// Ensure the collection name is not illegal
this.checkCollectionName(collectionName);
this.opts = options != null && ('object' === typeof options) ? options : {};
this.slaveOk = options == null || options.slaveOk == null ? db.slaveOk : options.slaveOk;
// debug("======================================================== options")
// debug(inspect(options))
this.pkFactory = pkFactory == null
? db.bson_serializer.ObjectID
: pkFactory;
Object.defineProperty(this, "hint", {
enumerable: true
, get: function () {
return this.internalHint;
}
, set: function (v) {
this.internalHint = this.normalizeHintField(v);
}
});
};
Collection.prototype.insert = function(docs, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
if(Object.prototype.toString.call(callback) != '[object Function]') {
args.push(callback)
callback = null
}
options = args.length ? args.shift() : {};
/**
* Inserts `docs` into the db.
*
* @param {Array|Object} docs
* @param {Object} options (optional)
* @param {Function} callback (optional)
* @return {Collection}
*/
Collection.prototype.insert = function insert (docs, options, callback) {
if ('function' === typeof options) callback = options, options = {};
this.insertAll(Array.isArray(docs) ? docs : [docs], options, callback);
return this;
};
Collection.prototype.checkCollectionName = function(collectionName) {
if (typeof collectionName != 'string')
/**
* Checks if `collectionName` is valid.
*
* @param {String} collectionName
*/
Collection.prototype.checkCollectionName = function checkCollectionName (collectionName) {
if ('string' !== typeof collectionName) {
throw Error("collection name must be a String");
}
if (!collectionName || collectionName.indexOf('..') != -1)
if (!collectionName || collectionName.indexOf('..') != -1) {
throw Error("collection names cannot be empty");
}
if (collectionName.indexOf('$') != -1 && collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null)
if (collectionName.indexOf('$') != -1 &&
collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) {
throw Error("collection names must not contain '$'");
}
if (collectionName.match(/^\.|\.$/) != null)
if (collectionName.match(/^\.|\.$/) != null) {
throw Error("collection names must not start or end with '.'");
}
};
Collection.prototype.remove = function(selector, options, callback) {
var args = Array.prototype.slice.call(arguments, 0);
callback = args.pop();
var removeSelector = args.length ? args.shift() : {};
options = args.length ? args.shift() : {};
/**
* Removes documents specified by `selector` from the db.
* @param {Object} selector (optional)
* @param {Object} options (optional)
* @param {Function} callback (optional)
*/
// Generate selector for remove all if not available
var deleteCommand = new DeleteCommand(this.db, this.db.databaseName + "." + this.collectionName, removeSelector);
Collection.prototype.remove = function remove (selector, options, callback) {
if ('function' === typeof selector) {
callback = selector;
selector = options = {};
} else if ('function' === typeof options) {
callback = options;
options = {};
}
var deleteCommand = new DeleteCommand(
this.db
, this.db.databaseName + "." + this.collectionName
, selector);
// Execute the command, do not add a callback as it's async
var result = this.db.executeCommand(deleteCommand);
if(result instanceof Error) {
if(callback != null) return callback(result, null);
}
// If safe mode check last error
if(callback != null) {
if(options.safe || this.db.strict) {
this.db.error(function(err, error) {
if(error[0].err) {
callback(new Error(error[0].err), null);
} else {
callback(null, null);
}
});
} else {
// Callback with no error check
callback(null, this);
if (options && options.safe || this.opts.safe != null || this.db.strict) {
var errorOptions = options.safe != null ? options.safe : null;
errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions;
errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions;
// Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
this.db.executeCommand(deleteCommand, {read:false, safe: errorOptions}, function (err, error) {
error = error && error.documents;
if(!callback) return;
if (err) {
callback(err);
} else if (error[0].err) {
callback(new Error(error[0].err));
} else {
callback(null, error[0].n);
}
});
} else {
var result = this.db.executeCommand(deleteCommand);
// If no callback just return
if (!callback) return;
// If error return error
if (result instanceof Error) {
return callback(result);
}
// Otherwise just return
return callback();
}
};
Collection.prototype.rename = function(collectionName, callback) {
/**
* Renames the collection.
*
* @param {String} newName
* @param {Function} callback
*/
Collection.prototype.rename = function rename (newName, callback) {
var self = this;
try {
this.checkCollectionName(collectionName);
this.db.renameCollection(this.collectionName, collectionName, function(err, result) {
if(err != null || result.documents[0].ok == 0) {
err != null ? callback(err, null) : callback(new Error(result.documents[0].errmsg), null);
this.checkCollectionName(newName);
this.db.renameCollection(this.collectionName, newName, function (err, result) {
if (err) {
callback(err);
} else if (result.documents[0].ok == 0) {
callback(new Error(result.documents[0].errmsg));
} else {
// Set collectionname to new one and return the collection
self.db.collection(collectionName, callback);
self.db.collection(newName, callback);
}
});
} catch(err) {
callback(err, null);
} catch (err) {
callback(err);
}
};
Collection.prototype.insertAll = function(docs, options, callback) {
var self = this;
var error= null;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
/**
* Insert many docs into the db.
*
* @param {Array} docs
* @param {Object} options (optional)
* @param {Function} callback (optional)
*/
if(Object.prototype.toString.call(callback) != '[object Function]') {
args.push(callback)
callback = null
}
Collection.prototype.insertAll = function insertAll (docs, options, callback) {
if ('function' === typeof options) callback = options, options = {};
options = args.length ? args.shift() : {};
var insertCommand = new InsertCommand(
this.db
, this.db.databaseName + "." + this.collectionName);
// List of all id's inserted
var objects = [];
// Create an insert command
var insertCommand = new InsertCommand(this.db, this.db.databaseName + "." + this.collectionName);
// Add id to each document if it's not already defined
for(var index = 0; index < docs.length; index++) {
// Add the documents and decorate them with id's if they have none
for (var index = 0, len = docs.length; index < len; ++index) {
var doc = docs[index];
// Add the id to the document
var id = doc["_id"] == null ? this.pkFactory.createPk() : doc["_id"];
doc['_id'] = id;
// Insert the document
// Add id to each document if it's not already defined
if (!doc['_id'] && this.db.forceServerObjectId != true) {
doc['_id'] = this.pkFactory.createPk();
}
insertCommand.add(doc);
objects.push(doc);
}
// Execute the command
var result = this.db.executeCommand(insertCommand);
if(result instanceof Error) {
if(callback != null) return callback(result, null);
}
// If safe is defined check for error message
if(callback != null) {
if(options.safe || this.db.strict) {
this.db.error(function(err, error) {
if(error[0].err) {
if(callback != null) callback(new Error(error[0].err), null);
} else {
if(callback != null) callback(null, objects);
}
});
} else {
if(callback != null) callback(null, objects);
if (options != null && (options.safe == true || this.db.strict == true || this.opts.safe == true)) {
var errorOptions = options.safe != null ? options.safe : null;
errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions;
errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions;
// Insert options
var insertOptions = {read:false, safe: errorOptions};
// If we have safe set set async to false
if(errorOptions == null) insertOptions['async'] = true;
// Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
this.db.executeCommand(insertCommand, insertOptions, function (err, error) {
error = error && error.documents;
if(!callback) return;
if (err) {
callback(err);
} else if (error[0].err) {
callback(new Error(error[0].err));
} else {
callback(null, docs);
}
});
} else {
var result = this.db.executeCommand(insertCommand);
// If no callback just return
if (!callback) return;
// If error return error
if (result instanceof Error) {
return callback(result);
}
// Otherwise just return
return callback(null, docs);
}
};
Collection.prototype.save = function(doc, options, callback) {
/**
* Save a document.
*
* @param {Object} doc
* @param {Object} options (optional)
* @param {Function} callback (optional)
*/
Collection.prototype.save = function save (doc, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
if(Object.prototype.toString.call(callback) != '[object Function]') {
args.push(callback)
callback = null
}
options = args.length ? args.shift() : null;
var errorOptions = options.safe != null ? options.safe : false;
errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions;
var id = doc['_id'];
if(id != null) {
this.update({'_id':id}, doc, {upsert: true, safe: options != null ? options.safe : false}, callback);
if (id) {
this.update({ _id: id }, doc, { upsert: true, safe: errorOptions }, callback);
} else {
this.insert(doc, {safe: options != null ? options.safe : false}, function(err, docs) { Array.isArray(docs) ? callback(err, docs[0]) : callback(err, docs); });
this.insert(doc, { safe: errorOptions }, callback && function (err, docs) {
if (err) return callback(err, null);
if (Array.isArray(docs)) {
callback(err, docs[0]);
} else {
callback(err, docs);
}
});
}

@@ -206,63 +319,57 @@ };

/**
Update a single document in this collection.
spec - a associcated array containing the fields that need to be present in
the document for the update to succeed
* Updates documents.
*
* By default updates only the first found doc. To update all matching
* docs in the db, set options.multi to true.
*
* @param {Object} selector
* @param {Object} document - the fields/vals to be updated, or in the case of
* an upsert operation, inserted.
* @param {Object} options (optional)
* upsert - {bool} perform an upsert operation
* multi - {bool} update all documents matching the selector
* safe - {bool} check if the update failed (requires extra call to db)
* @param {Function} callback (optional)
*/
document - an associated array with the fields to be updated or in the case of
a upsert operation the fields to be inserted.
Collection.prototype.update = function update (selector, document, options, callback) {
if('function' === typeof options) callback = options, options = null;
Options:
upsert - true/false (perform upsert operation)
multi - true/false (update all documents matching spec)
safe - true/false (perform check if the operation failed, required extra call to db)
**/
Collection.prototype.update = function(spec, document, options, callback) {
var args = Array.prototype.slice.call(arguments, 2);
callback = args.pop();
var updateCommand = new UpdateCommand(
this.db
, this.db.databaseName + "." + this.collectionName
, selector
, document
, options);
if(Object.prototype.toString.call(callback) != '[object Function]') {
args.push(callback)
callback = null
}
options = args.length ? args.shift() : null;
var safe = options == null || options.safe == null || options.safe == false ? false : true;
var upsert = options == null || options.upsert == null || options.upsert == false ? false : true;
// Create update command
var updateCommand = new UpdateCommand(this.db, this.db.databaseName + "." + this.collectionName, spec, document, options);
// Execute command
var result = this.db.executeCommand(updateCommand);;
if(result instanceof Error) {
if(callback != null) return callback(result, null);
}
// If safe, we need to check for successful execution
if(safe || this.db.strict) {
this.db.error(function(err, error) {
if(callback != null) {
if (upsert) {
// Document was either inserted or updated, simply pass on the error if one occurred.
if (error[0].err) {
if(callback != null) callback(new Error(error[0].err), null);
} else {
if(callback != null) callback(null, document);
}
} else {
// Update only doesn't return an error when the record to be updated doesn't exist.
if(error[0].updatedExisting == false) {
if(callback != null) callback(new Error("Failed to update document"), null);
} else {
// If another kind of error occurred then report it to the callback function.
if (error[0].err) {
if(callback != null) callback(new Error(error[0].err), null);
} else {
if(callback != null) callback(null, document);
}
}
}
}
});
// If we are executing in strict mode or safe both the update and the safe command must happen on the same line
if (options && options.safe || this.db.strict || this.opts.safe) {
// Unpack the error options if any
var errorOptions = (options && options.safe != null) ? options.safe : null;
errorOptions = errorOptions == null && this.opts.safe != null ? this.opts.safe : errorOptions;
errorOptions = errorOptions == null && this.db.strict != null ? this.db.strict : errorOptions;
// Execute command with safe options (rolls up both command and safe command into one and executes them on the same connection)
this.db.executeCommand(updateCommand, {read:false, safe: errorOptions}, function (err, error) {
error = error && error.documents;
if(!callback) return;
if (err) {
callback(err);
} else if (error[0].err) {
callback(new Error(error[0].err));
} else {
callback(null, error[0].n);
}
});
} else {
// Call back with ok if no error found
if(callback != null) callback(null, document);
var result = this.db.executeCommand(updateCommand);
// If no callback just return
if (!callback) return;
// If error return error
if (result instanceof Error) {
return callback(result);
}
// Otherwise just return
return callback();
}

@@ -272,30 +379,65 @@ };

/**
Fetch a distinct collection
**/
Collection.prototype.distinct = function(key, query, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
query = args.length ? args.shift() : {};
* Fetch a distinct collection
* @param {String} key
* @param {Object} query (optional)
* @param {Function} callback (optional)
*/
var mapCommandHash = {distinct:this.collectionName, key:key, query:query};
this.db.executeCommand(DbCommand.createDbCommand(this.db, mapCommandHash), function(err, result) {
if(err == null && result.documents[0].ok == 1) {
callback(null, result.documents[0].values);
} else {
err != null ? callback(err, null) : callback(new Error(result.documents[0].errmsg), null);
Collection.prototype.distinct = function distinct (key, query, callback) {
if ('function' === typeof query) callback = query, query = {};
var mapCommandHash = {
distinct: this.collectionName
, query: query
, key: key
};
var cmd = DbCommand.createDbCommand(this.db, mapCommandHash);
this.db.executeCommand(cmd, {read:true}, function (err, result) {
if (err) {
return callback(err);
}
if (result.documents[0].ok != 1) {
return callback(new Error(result.documents[0].errmsg));
}
callback(null, result.documents[0].values);
});
};
Collection.prototype.count = function(query, callback) {
if(typeof query === "function") { callback = query; query = null; }
var query_object = query == null ? {} : query;
var final_query = {count: this.collectionName, query: query_object, fields: null};
var queryCommand = new QueryCommand(this.db, this.db.databaseName + ".$cmd", QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, final_query, null);
// Execute the command
this.db.executeCommand(queryCommand, function(err, result) {
if(err == null && result.documents[0].ok == 1) {
/**
* Count number of matching documents in the db.
*
* @param {Object} query
* @param {Function} callback
*/
Collection.prototype.count = function count (query, callback) {
if ('function' === typeof query) callback = query, query = {};
var final_query = {
count: this.collectionName
, query: query
, fields: null
};
var queryCommand = new QueryCommand(
this.db
, this.db.databaseName + ".$cmd"
, QueryCommand.OPTS_NO_CURSOR_TIMEOUT
, 0
, -1
, final_query
, null
);
this.db.executeCommand(queryCommand, {read:true}, function (err, result) {
if (err) {
callback(err);
} else if (result.documents[0].ok != 1) {
callback(new Error(result.documents[0].errmsg));
} else {
callback(null, result.documents[0].n);
} else {
err != null ? callback(err, null) : callback(new Error(result.documents[0].errmsg), null);
}

@@ -305,3 +447,9 @@ });

Collection.prototype.drop = function(callback) {
/**
* Drop this collection.
*
* @param {Function} callback
*/
Collection.prototype.drop = function drop (callback) {
this.db.dropCollection(this.collectionName, callback);

@@ -311,45 +459,47 @@ };

/**
Fetch and update a collection
query: a filter for the query
sort: if multiple docs match, choose the first one in the specified sort order as the object to manipulate
update: an object describing the modifications to the documents selected by the query
options:
remove: set to a true to remove the object before returning
new: set to true if you want to return the modified object rather than the original. Ignored for remove.
upsert: true/false (perform upsert operation)
**/
Collection.prototype.findAndModify = function(query, sort, update, options, callback) {
* Find and update a document.
*
* @param {Object} query
* @param {Array} sort - if multiple docs match, choose the first one
* in the specified sort order as the object to manipulate
* @param {Object} doc - the fields/vals to be updated
* @param {Object} options -
* remove: {Bool} set to true to remove the object before returning
* upsert: {Bool} perform an upsert operation
* new: {Bool} set to true if you want to return the modified object
* rather than the original. Ignored for remove.
* @param {Function} callback
*/
Collection.prototype.findAndModify = function findAndModify (query, sort, doc, options, callback) {
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
sort = args.length ? args.shift() : [];
update = args.length ? args.shift() : null;
doc = args.length ? args.shift() : null;
options = args.length ? args.shift() : {};
// Format the sort object
var sort_object = formattedOrderClause(sort);
// Unpack the options
var queryOptions = QueryCommand.OPTS_NONE;
// Build the query object for the findAndModify
var queryObject = {
'findandmodify': this.collectionName,
'query':query,
'sort':sort_object
}
'findandmodify': this.collectionName
, 'query': query
, 'sort': formattedOrderClause(sort)
};
queryObject['new'] = options['new'] ? 1 : 0;
queryObject['remove'] = options.remove ? 1 : 0;
queryObject['upsert'] = options.upsert ? 1 : 0;
if (options.fields) queryObject['fields'] = options.fields;
queryObject.new = options.new ? 1 : 0;
queryObject.remove = options.remove ? 1 : 0;
queryObject.upsert = options.upsert ? 1 : 0;
// Set up the update if it exists
if(update) queryObject['update'] = update;
if (options.fields) {
queryObject.fields = options.fields;
}
// Set up the sort
if(!Array.isArray(sort) && sort.length == 0) queryObject['sort'] = sort_object;
if (doc && !options.remove) {
queryObject.update = doc;
}
if(options.remove) delete queryObject['update'];
// Execute command
this.db.executeDbCommand(queryObject, function(err, doc) {
err ? callback(err, doc) : callback(err, doc.documents[0].value);
this.db.executeDbCommand(queryObject, function (err, doc) {
if (err) {
callback(err, doc)
} else {
callback(err, doc.documents[0].value)
}
});

@@ -360,2 +510,3 @@ }

* Various argument possibilities
* TODO : combine/reduce # of possibilities
* 1 callback?

@@ -373,13 +524,15 @@ * 2 selector, callback?,

*/
Collection.prototype.find = function() {
var options,
args = Array.prototype.slice.call(arguments, 0),
has_callback = typeof args[args.length - 1] === 'function',
has_weird_callback = typeof args[0] === 'function',
callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null),
len = args.length,
selector = (len >= 1) ? args[0] : {},
fields = (len >= 2) ? args[1] : undefined;
if(len == 1 && has_weird_callback) { // backwards compat for callback?, options case
Collection.prototype.find = function find () {
var options
, args = Array.prototype.slice.call(arguments, 0)
, has_callback = typeof args[args.length - 1] === 'function'
, has_weird_callback = typeof args[0] === 'function'
, callback = has_callback ? args.pop() : (has_weird_callback ? args.shift() : null)
, len = args.length
, selector = len >= 1 ? args[0] : {}
, fields = len >= 2 ? args[1] : undefined;
if (len === 1 && has_weird_callback) {
// backwards compat for callback?, options case
selector = {};

@@ -389,21 +542,43 @@ options = args[0];

if(len == 2){ // backwards compat for options object
var test = ['limit','sort','fields','skip','hint','explain','snapshot','timeout','tailable', 'batchSize'],
idx = 0, l = test.length, is_option = false;
while(!is_option && idx < l) if(test[idx] in fields ) is_option = true; else idx++;
options = is_option ? fields : {};
if(is_option) fields = undefined;
if (len === 2) {
// backwards compat for options object
var test = ['limit','sort','fields','skip','hint','explain','snapshot','timeout','tailable', 'batchSize']
, is_option = false;
for (var idx = 0, l = test.length; idx < l; ++idx) {
if (test[idx] in fields) {
is_option = true;
break;
}
}
if (is_option) {
options = fields;
fields = undefined;
} else {
options = {};
}
}
if(len == 3) options = args[2];
if(options && options.fields){
if (3 === len) {
options = args[2];
}
if (options && options.fields) {
fields = {};
if(options.fields.constructor == Array){
if(options.fields.length == 0) fields['_id'] = 1;
else for(var i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1;
if (Array.isArray(options.fields)) {
if (!options.fields.length) {
fields['_id'] = 1;
} else {
for (var i = 0, l = options.fields.length; i < l; i++) {
fields[options.fields[i]] = 1;
}
}
} else {
fields = options.fields;
}
else fields = options.fields;
}
if(!options) options = {};
if (!options) options = {};
options.skip = len > 3 ? args[2] : options.skip ? options.skip : 0;

@@ -413,3 +588,4 @@ options.limit = len > 3 ? args[3] : options.limit ? options.limit : 0;

options.timeout = len == 5 ? args[4] : options.timeout ? options.timeout : undefined;
options.slaveOk = options.slaveOk != null ? options.slaveOk : false;
// If we have overridden slaveOk otherwise use the default db setting
options.slaveOk = options.slaveOk != null ? options.slaveOk : this.db.slaveOk;

@@ -420,2 +596,3 @@ var o = options;

if (callback) {
// TODO refactor Cursor args
callback(null, new Cursor(this.db, this, selector, fields, o.skip, o.limit, o.sort, o.hint, o.explain, o.snapshot, o.timeout, o.tailable, o.batchSize, o.slaveOk));

@@ -427,75 +604,160 @@ } else {

Collection.prototype.normalizeHintField = function(hint) {
/**
* Normalizes a `hint` argument.
*
* @param {String|Object|Array} hint
* @return {Object}
*/
Collection.prototype.normalizeHintField = function normalizeHintField (hint) {
var finalHint = null;
// Normalize the hint parameter
if(hint != null && hint.constructor == String) {
finalHint = {};
finalHint[hint] = 1;
} else if(hint != null && hint.constructor == Object) {
finalHint = {};
for(var name in hint) { finalHint[name] = hint[name]; }
} else if(hint != null && hint.constructor == Array) {
finalHint = {};
hint.forEach(function(param) { finalHint[param] = 1; });
if (null != hint) {
switch (hint.constructor) {
case String:
finalHint = {};
finalHint[hint] = 1;
break;
case Object:
finalHint = {};
for (var name in hint) {
finalHint[name] = hint[name];
}
break;
case Array:
finalHint = {};
hint.forEach(function(param) {
finalHint[param] = 1;
});
break;
}
}
return finalHint;
};
Collection.prototype.findOne = function(queryObject, options, callback) {
var args = Array.prototype.slice.call(arguments, 0);
callback = args.pop();
queryObject = args.length ? args.shift() : {};
options = args.length ? args.shift() : {};
/**
* Finds one document.
*
* @param {Object} queryQbject
* @param {Object} options
* @param {Function} callback
*/
var fields = options.fields;
// Normalize fields filtering
if(options && options.fields){
Collection.prototype.findOne = function findOne (queryObject, options, callback) {
if ('function' === typeof queryObject) {
callback = queryObject;
queryQbject = {};
options = {};
} else if ('function' === typeof options) {
callback = options;
options = {};
}
var fields;
if (options.fields && Array.isArray(options.fields)) {
fields = {};
if(options.fields.constructor == Array){
if(options.fields.length == 0) fields['_id'] = 1;
else for(var i = 0, l = options.fields.length; i < l; i++) fields[options.fields[i]] = 1;
if (0 === options.fields.length) {
fields['_id'] = 1;
} else {
for (var i = 0, len = options.fields.length; i < len; ++i) {
fields[options.fields[i]] = 1;
}
}
else fields = options.fields;
} else {
fields = options.fields;
}
// Unpack the options
var timeout = options.timeout != null ? options.timeout : QueryCommand.OPTS_NONE;
var queryOptions = timeout;
// Build final query
var finalQueryObject = queryObject == null ? {} : queryObject;
// Validate the type of query
finalQueryObject = (finalQueryObject instanceof this.db.bson_serializer.ObjectID || Object.prototype.toString.call(finalQueryObject) === '[object ObjectID]') ? {'_id':finalQueryObject} : finalQueryObject;
// Build special selector
var specialSelector = {'query':finalQueryObject};
// Build full collection name
var collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collectionName;
// Execute the command
var queryCommand = new QueryCommand(this.db, collectionName, queryOptions, 0, 1, specialSelector, fields);
this.db.executeCommand(queryCommand, function(err, result) {
if(!err && result.documents[0] && result.documents[0]['$err']) return callback(result.documents[0]['$err'], null);
callback(err, result.documents[0]);
if (queryObject instanceof this.db.bson_serializer.ObjectID ||
'[object ObjectID]' === toString.call(queryObject)) {
queryObject = { '_id': queryObject };
}
var query = { 'query': queryObject };
var timeout = null != options.timeout
? options.timeout
: QueryCommand.OPTS_NONE;
var collectionName = (this.db.databaseName ? this.db.databaseName + '.' : '')
+ this.collectionName;
var queryCommand = new QueryCommand(
this.db
, collectionName
, timeout
, 0
, 1
, query
, fields);
this.db.executeCommand(queryCommand, {read:true}, function (err, result) {
if (!err && result.documents[0] && result.documents[0]['$err']) {
return callback(result.documents[0]['$err']);
}
callback(err, result && result.documents && result.documents[0]);
});
};
Collection.prototype.createIndex = function(fieldOrSpec, unique, callback) {
this.db.createIndex(this.collectionName, fieldOrSpec, unique, callback);
/**
* Creates an index on this collection.
*
* @param {Object} fieldOrSpec
* @param {Object} options
* @param {Function} callback
*/
Collection.prototype.createIndex = function createIndex (fieldOrSpec, options, callback) {
this.db.createIndex(this.collectionName, fieldOrSpec, options, callback);
};
Collection.prototype.ensureIndex = function(fieldOrSpec, unique, callback) {
this.db.ensureIndex(this.collectionName, fieldOrSpec, unique, callback);
/**
* Ensures the index exists on this collection.
*
* @param {Object} fieldOrSpec
* @param {Object} options
* @param {Function} callback
*/
Collection.prototype.ensureIndex = function ensureIndex (fieldOrSpec, options, callback) {
this.db.ensureIndex(this.collectionName, fieldOrSpec, options, callback);
};
Collection.prototype.indexInformation = function(callback) {
/**
* Retrieves this collections index info.
*
* @param {Function} callback
*/
Collection.prototype.indexInformation = function indexInformation (callback) {
this.db.indexInformation(this.collectionName, callback);
};
Collection.prototype.dropIndex = function(indexName, callback) {
this.db.dropIndex(this.collectionName, indexName, callback);
/**
* Drops an index from this collection.
*
* @param {String} name
* @param {Function} callback
*/
Collection.prototype.dropIndex = function dropIndex (name, callback) {
this.db.dropIndex(this.collectionName, name, callback);
};
Collection.prototype.dropIndexes = function(callback) {
this.db.dropIndex(this.collectionName, "*", function(err, result) {
if(err == null && result.documents[0].ok == 1) {
/**
* Drops all indexes from this collection.
*
* @param {Function} callback
*/
Collection.prototype.dropIndexes = function dropIndexes (callback) {
this.db.dropIndex(this.collectionName, '*', function (err, result) {
if (err) {
callback(err);
} else if (1 == result.documents[0].ok) {
callback(null, true);
} else {
err != null ? callback(err, null) : callback(new Error("map-reduce failed: " + result.documents[0].errmsg), false);
callback(new Error("map-reduce failed: " + result.documents[0].errmsg), false);
}

@@ -505,49 +767,123 @@ });

Collection.prototype.mapReduce = function(map, reduce, options, callback) {
var args = Array.prototype.slice.call(arguments, 2);
callback = args.pop();
var self = this;
// Parse version of server if available
var version = this.db.version != null ? parseInt(this.db.version.replace(/\./g, '')) : 0;
/**
* Map reduce.
*
* @param {Function|String} map
* @param {Function|String} reduce
* @param {Objects} options
* @param {Function} callback
*/
Collection.prototype.mapReduce = function mapReduce (map, reduce, options, callback) {
if ('function' === typeof options) callback = options, options = {};
// Set default to be inline if we are dealing with a v 1.7.6 > server
if(version > 0 && version > 176) {
options = args.length ? args.shift() : {out:'inline'};
if(options.out == null) options.out = 'inline';
var version = 'string' === typeof this.db.version
? parseInt(this.db.version.replace(/\./g, ''))
: 0;
if (version > 0 && version > 176) {
if (null == options.out) options.out = 'inline';
}
if(Object.prototype.toString.call(map) === '[object Function]') map = map.toString();
if(Object.prototype.toString.call(reduce) === '[object Function]') reduce = reduce.toString();
// Build command object for execution
var mapCommandHash = {mapreduce:this.collectionName, map:map, reduce:reduce};
if ('function' === typeof map) {
map = map.toString();
}
if ('function' === typeof reduce) {
reduce = reduce.toString();
}
if ('function' === typeof options.finalize) {
options.finalize = options.finalize.toString();
}
var mapCommandHash = {
mapreduce: this.collectionName
, map: map
, reduce: reduce
};
// Add any other options passed in
for(var name in options) {
for (var name in options) {
mapCommandHash[name] = options[name];
}
// Execute command against server
this.db.executeCommand(DbCommand.createDbCommand(this.db, mapCommandHash), function(err, result) {
if(err == null && result.documents[0].ok == 1) {
//return the results, if the map/reduce is invoked with inline option
if(result.documents[0].results) {
return callback(err, result.documents[0].results);
var self = this;
var cmd = DbCommand.createDbCommand(this.db, mapCommandHash);
this.db.executeCommand(cmd, {read:true}, function (err, result) {
if (err) {
return callback(err);
}
if (1 != result.documents[0].ok) {
return callback(result.documents[0]);
}
// invoked with inline?
if (result.documents[0].results) {
return callback(null, result.documents[0].results);
}
// Create a collection object that wraps the result collection
self.db.collection(result.documents[0].result, function (err, collection) {
if (!options.include_statistics) {
return callback(err, collection);
}
// Create a collection object that wraps the result collection
self.db.collection(result.documents[0].result, function(err, collection) {
if(options.include_statistics) {
var stats = {
processtime: result.documents[0].timeMillis,
counts: result.documents[0].counts
};
callback(err, collection, stats);
} else {
callback(err, collection);
}
});
} else {
err != null ? callback(err, null, null) : callback(result.documents[0], null, null);
}
var stats = {
processtime: result.documents[0].timeMillis
, counts: result.documents[0].counts
};
callback(err, collection, stats);
});
});
};
Collection.prototype.group = function(keys, condition, initial, reduce, command, callback) {
/**
* Group function helper
*/
var groupFunction = function () {
var c = db[ns].find(condition);
var map = new Map();
var reduce_function = reduce;
while (c.hasNext()) {
var obj = c.next();
var key = {};
for (var i = 0, len = keys.length; i < len; ++i) {
var k = keys[i];
key[k] = obj[k];
}
var aggObj = map.get(key);
if (aggObj == null) {
var newObj = Object.extend({}, key);
aggObj = Object.extend(newObj, initial);
map.put(key, aggObj);
}
reduce_function(obj, aggObj);
}
return { "result": map.values() };
}.toString();
/**
* Group.
*
* @param {Object|Array|Function|Code} keys
* @param {TODO} condition
* @param {TODO} initial
* @param {Function|Code} reduce
* @param {Boolean} command
* @param {Function} callback
*/
Collection.prototype.group = function group (keys, condition, initial, reduce, command, callback) {
var args = Array.prototype.slice.call(arguments, 3);

@@ -558,24 +894,33 @@ callback = args.pop();

if(command) {
var hash = {},
reduceFunction = reduce != null && reduce instanceof this.db.bson_serializer.Code ? reduce : new this.db.bson_serializer.Code(reduce);
var Code = this.db.bson_serializer.Code
if (!Array.isArray(keys) && keys instanceof Object && typeof(keys) !== 'function') {
keys = Object.keys(keys);
}
if (reduce instanceof Function) {
reduce = reduce.toString();
}
if (command) {
var reduceFunction = reduce instanceof Code
? reduce
: new Code(reduce);
var selector = {
group:
{
'ns': this.collectionName,
'$reduce': reduceFunction,
'cond': condition,
'initial': initial
group: {
'ns': this.collectionName
, '$reduce': reduceFunction
, 'cond': condition
, 'initial': initial
}
};
if(keys.constructor == Function)
{
var keyFunction = keys != null && keys instanceof this.db.bson_serializer.Code ? keys : new this.db.bson_serializer.Code(keys);
selector.group.$keyf = keyFunction;
}
else
{
keys.forEach(function(key) {
if ('function' === typeof keys) {
selector.group.$keyf = keys instanceof Code
? keys
: new Code(keys);
} else {
var hash = {};
keys.forEach(function (key) {
hash[key] = 1;

@@ -585,57 +930,33 @@ });

}
this.db.executeCommand(DbCommand.createDbCommand(this.db, selector), function(err, result) {
var cmd = DbCommand.createDbCommand(this.db, selector);
this.db.executeCommand(cmd, {read:true}, function (err, result) {
if (err) return callback(err);
var document = result.documents[0];
if(err == null && document.retval != null) {
callback(null, document.retval);
} else {
err != null ? callback(err, null) : callback(new Error("group command failed: " + document.errmsg), null);
if (null == document.retval) {
return callback(new Error("group command failed: " + document.errmsg));
}
callback(null, document.retval);
});
} else {
// Create execution scope
var scope = reduce != null && reduce instanceof this.db.bson_serializer.Code ? reduce.scope : {};
// Create scope for execution
scope['ns'] = this.collectionName;
scope['keys'] = keys;
scope['condition'] = condition;
scope['initial'] = initial;
// Define group function
var groupFunction = function() {
var c = db[ns].find(condition);
var map = new Map();
var reduce_function = reduce;
while (c.hasNext()) {
var obj = c.next();
var scope = reduce != null && reduce instanceof Code
? reduce.scope
: {};
var key = {};
for (var i = 0; i < keys.length; i++) {
var k = keys[i];
key[k] = obj[k];
}
scope.ns = this.collectionName;
scope.keys = keys;
scope.condition = condition;
scope.initial = initial;
var aggObj = map.get(key);
if (aggObj == null) {
var newObj = Object.extend({}, key);
aggObj = Object.extend(newObj, initial);
map.put(key, aggObj);
}
reduce_function(obj, aggObj);
}
return {"result": map.values()};
};
// Pass in the function text to execute within mongodb.
var groupfn = groupFunction.replace(/ reduce;/, reduce.toString() + ';');
// Turn function into text and replace the "result" function of the grouping function
var groupFunctionString = groupFunction.toString().replace(/ reduce;/, reduce.toString() + ';');
// Execute group
this.db.eval(new this.db.bson_serializer.Code(groupFunctionString, scope), function(err, results) {
if(err != null) {
callback(err, null);
} else {
if(results.constructor == Object) {
callback(err, results.result);
} else {
callback(err, results);
}
}
this.db.eval(new Code(groupfn, scope), function (err, results) {
if (err) return callback(err, null);
callback(null, results.result || results);
});

@@ -645,9 +966,21 @@ }

Collection.prototype.options = function(callback) {
this.db.collectionsInfo(this.collectionName, function(err, cursor) {
// Fetch the object from the cursor
cursor.nextObject(function(err, document) {
callback(null, (document != null ? document.options : document));
/**
* Options.
*
* @param {Function} callback
*/
Collection.prototype.options = function options (callback) {
this.db.collectionsInfo(this.collectionName, function (err, cursor) {
if (err) return callback(err);
cursor.nextObject(function (err, document) {
callback(err, document && document.options || null);
});
});
};
/**
* Expose.
*/
exports.Collection = Collection;
var QueryCommand = require('./query_command').QueryCommand,
InsertCommand = require('./insert_command').InsertCommand,
MD5 = require('../crypto/md5').MD5,
inherits = require('sys').inherits;
inherits = require('util').inherits,
debug = require('util').debug,
inspect = require('util').inspect;

@@ -46,6 +48,9 @@ /**

var hash_password = MD5.hex_md5(username + ":mongo:" + password);
// debug("=========================== hash_password :: " + hash_password)
var key = MD5.hex_md5(nonce + username + hash_password);
// debug("=========================== pre_hash_key :: " + (nonce + username + hash_password))
// debug("=========================== key :: " + key)
var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key};
// Create db command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null);
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null);
};

@@ -77,9 +82,25 @@

DbCommand.createGetLastErrorCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getlasterror':1}, null);
DbCommand.createGetLastErrorCommand = function(options, db) {
var args = Array.prototype.slice.call(arguments, 0);
db = args.pop();
options = args.length ? args.shift() : {};
// 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]
}
}
// debug("createGetLastErrorCommand :: " + inspect(command))
// Execute command
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null);
};
DbCommand.createGetLastStatusCommand = function(db) {
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getlasterror':1}, null);
};
DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand;
// function(db) {
// return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getlasterror':1}, null);
// };

@@ -94,7 +115,16 @@ DbCommand.createGetPreviousErrorsCommand = function(db) {

DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, unique) {
var finalUnique = unique == null ? false : unique;
DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) {
var finalUnique = options == null && !(options instanceof Object) ? false : options;
var fieldHash = {};
var indexes = [];
var keys;
var sparse;
var background;
// If the options is a hash
if(options instanceof Object) {
finalUnique = options['unique'] != null ? options['unique'] : false;
sparse = options['sparse'] != null ? options['sparse'] : false;
background = options['background'] != null ? options['background'] : false;
}

@@ -136,3 +166,6 @@ // Get all the fields accordingly

// Build the selector
var selector = {'ns':(db.databaseName + "." + collectionName), 'unique':finalUnique, 'key':fieldHash, 'name':indexName};
var selector = {'ns':(db.databaseName + "." + collectionName), 'key':fieldHash, 'name':indexName};
selector['unique'] = finalUnique;
selector['sparse'] = sparse;
selector['background'] = background;
// Create the insert command for the index and return the document

@@ -153,1 +186,5 @@ return new InsertCommand(db, db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION, false).add(selector);

};
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);
};
var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits;

@@ -5,0 +5,0 @@ /**

var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits;

@@ -5,0 +5,0 @@ /**

var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits,
debug = require('util').debug,
inspect = require('util').inspect;

@@ -25,2 +27,3 @@ /**

InsertCommand.prototype.getOpCode = function() {
return BaseCommand.OP_INSERT;

@@ -39,3 +42,3 @@ };

var command_string = '';
for(var i = 0; i < this.documents.length; i++) {
for(var i = 0; i < this.documents.length; i++) {
command_string = command_string + this.db.bson_serializer.BSON.serialize(this.documents[i], this.checkKeys);

@@ -42,0 +45,0 @@ }

var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits;

@@ -5,0 +5,0 @@ /**

var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits;

@@ -54,2 +54,4 @@ /**

QueryCommand.OPTS_OPLOG_REPLY = 8;
QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
QueryCommand.OPTS_AWAIT_DATA = 32;
QueryCommand.OPTS_EXHAUST = 64;
var BaseCommand = require('./base_command').BaseCommand,
BinaryParser = require('../bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits;

@@ -5,0 +5,0 @@ /**

var net = require('net'),
debug = require('util').debug,
inspect = require('util').inspect,
EventEmitter = require("events").EventEmitter,
BinaryParser = require('./bson/binary_parser').BinaryParser,
inherits = require('sys').inherits;
inherits = require('util').inherits,
Server = require('./connections/server').Server;
var Connection = exports.Connection = function(host, port, autoReconnect) {
var Connection = exports.Connection = function(host, port, autoReconnect, options) {
this.options = options == null ? {} : options;
this.host = host;

@@ -11,6 +15,7 @@ this.port = port;

this.drained = true;
// Fetch the poolsize
this.poolSize = this.options["poolSize"] == null ? 1 : this.options["poolSize"];
// Reconnect buffer for messages
this.messages = [];
// Message sender
var self = this;
// Status messages

@@ -21,2 +26,8 @@ this.sizeOfMessage = 0;

this.stubBuffer = '';
this.connected = false;
// Connection pool variables
this.pool = [];
this.poolByReference = {};
this.poolIndex = 0;
};

@@ -26,56 +37,53 @@

// Functions to open the connection
Connection.prototype.open = function() {
// Assign variable to point to local scope object
var self = this;
// Create the associated connection
this.connection = net.createConnection(this.port, this.host);
// Set up the net client
this.connection.setEncoding("binary");
// Add connnect listener
this.connection.addListener("connect", function() {
this.setEncoding("binary");
this.setTimeout(0);
this.setNoDelay();
self.emit("connect");
});
this.connection.addListener("error", function(err) {
self.emit("error", err);
});
this.connection.addListener("timeout", function(err) {
self.emit("timeout", err);
});
// Add a close listener
this.connection.addListener("close", function() {
self.emit("close");
});
// Listener for receive data
this.receiveListener = function(result) {
var getConnection = function(self) {
return self.pool[self.poolIndex++ % self.pool.length];
}
// Setup the connection pool
var setupConnectionPool = function(self, poolSize, reconnect) {
// Pool off connections and status variables
var connectionPool = [];
var connectedTo = 0;
var errors = 0;
var connectionError = null;
//
// Listener that handles callbacks for the connection
// Uses the internal object states to keep individual tcp connections seperate
var receiveListener = function(result, fd) {
fd = fd == null ? this.fd : fd;
// Fetch the pool reference
var conObj = self.poolByReference[fd];
// if(conObj == null) {
// debug("================================================================ failed to find connection :: " + this.fd)
// debug(inspect(self.poolByReference))
// }
// Check if we have an unfinished message
if(self.bytesRead > 0 && self.sizeOfMessage > 0) {
if(conObj != null && conObj.bytesRead > 0 && conObj.sizeOfMessage > 0) {
// Calculate remaing bytes to fetch
var remainingBytes = self.sizeOfMessage - self.bytesRead;
var remainingBytes = conObj.sizeOfMessage - conObj.bytesRead;
// Check if we have multiple packet messages and save the pieces otherwise emit the message
if(remainingBytes > result.length) {
self.buffer = self.buffer + result; self.bytesRead = self.bytesRead + result.length;
conObj.buffer = conObj.buffer + result; conObj.bytesRead = conObj.bytesRead + result.length;
} else {
// Cut off the remaining message
self.buffer = self.buffer + result.substr(0, remainingBytes);
conObj.buffer = conObj.buffer + result.substr(0, remainingBytes);
// Emit the message
self.emit("data", self.buffer);
self.emit("data", conObj.buffer);
// Reset the variables
self.buffer = ''; self.bytesRead = 0; self.sizeOfMessage = 0;
conObj.buffer = ''; conObj.bytesRead = 0; conObj.sizeOfMessage = 0;
// If message is longer than the current one, keep parsing
if(remainingBytes < result.length) {
self.receiveListener(result.substr(remainingBytes, (result.length - remainingBytes)));
// debug("--------------------------------------- remainingBytes < result.length :: " + this.fd)
// receiveListener.call(this, result.substr(remainingBytes, (result.length - remainingBytes)));
receiveListener(result.substr(remainingBytes, (result.length - remainingBytes)), fd);
}
}
} else {
if(self.stubBuffer.length > 0) {
result = self.stubBuffer + result;
self.stubBuffer = '';
} else if(conObj != null){
if(conObj.stubBuffer.length > 0) {
result = conObj.stubBuffer + result;
conObj.stubBuffer = '';
}

@@ -87,3 +95,3 @@

if(sizeOfMessage > result.length) {
self.buffer = self.buffer + result; self.bytesRead = result.length; self.sizeOfMessage = sizeOfMessage;
conObj.buffer = conObj.buffer + result; conObj.bytesRead = result.length; conObj.sizeOfMessage = sizeOfMessage;
} else if(sizeOfMessage == result.length) {

@@ -93,67 +101,177 @@ self.emit("data", result);

self.emit("data", result.substr(0, sizeOfMessage));
self.receiveListener(result.substr(sizeOfMessage, (result.length - sizeOfMessage)));
// debug("--------------------------------------- sizeOfMessage < result.length :: " + this.fd)
// receiveListener.call(this, result.substr(sizeOfMessage, (result.length - sizeOfMessage)));
receiveListener(result.substr(sizeOfMessage, (result.length - sizeOfMessage)), fd);
}
} else {
self.stubBuffer = result;
conObj.stubBuffer = result;
}
}
};
// Fill the pool
for(var i = 0; i < poolSize; i++) {
// Create the associated connection
var connection = net.createConnection(self.port, self.host);
// Set up the net client
connection.setEncoding("binary");
// Add connnect listener
connection.addListener("connect", function() {
this.setEncoding("binary");
this.setTimeout(0);
this.setNoDelay();
// Update number of connected to server
connectedTo = connectedTo + 1;
});
connection.addListener("error", function(err) {
// Update number of errors
errors = errors + 1;
connectionError = err;
});
connection.addListener("timeout", function(err) {
// Update number of errors
errors = errors + 1;
connectionError = err;
});
// Add a close listener
connection.addListener("close", function() {
self.emit("close");
});
// Add connection to the pool array
connectionPool.push({"connection": connection,
"sizeOfMessage": 0,
"bytesRead": 0,
"buffer": '',
"stubBuffer": ''});
// Add the listener to the connection
connection.addListener("data", receiveListener);
}
// Function that wait for connection to finish up
var waitForConnections = function() {
// Emit a connect message once all connections are up
if(connectedTo == connectionPool.length) {
if(reconnect == null || !reconnect) {
self.connected = true;
self.poolByReference = {};
// Save the connections by the fd reference
self.pool.forEach(function(con) {
self.poolByReference[con.connection.fd] = con;
});
self.emit("connect");
} else {
self.connected = false;
self.emit("reconnect");
}
} else if(errors + connectedTo == connectionPool.length) {
if(reconnect == null || !reconnect) {
self.connected = false;
self.emit("error", connectionError);
} else {
self.connected = false;
self.emit("reconnect");
}
} else {
process.nextTick(waitForConnections);
}
}
// Wait until we are done connected to all pool entries before emitting connect signal
process.nextTick(waitForConnections);
// Return the pool
return connectionPool;
}
// Add a receieved data connection
this.connection.addListener("data", this.receiveListener);
};
// Functions to open the connection
Connection.prototype.open = function() {
var self = this;
// Create the pool with connections
this.pool = setupConnectionPool(this, this.poolSize);
}
Connection.prototype.close = function() {
if(this.connection) this.connection.end();
this.connected = false;
// Close all entries in the pool
for(var i = 0; i < this.pool.length; i++) {
this.pool[i].connection.end();
}
};
Connection.prototype.send = function(command) {
Connection.prototype.send = function(command, rawConnection) {
var self = this;
// If we are executing the commnand on the entire pool
var connection = null;
// If we are forcing the use of a connection
if(rawConnection != null) {
connection = rawConnection;
} else {
connection = getConnection(self).connection;
}
// Check if the connection is closed
try {
if ( this.connection.readyState != "open" )
throw 'notConnected';
if(command.constructor == String) {
this.connection.write(command, "binary");
if (connection.readyState != "open") {
throw 'notConnected';
}
// Send the command, if it's an array of commands execute them all on the same connection
if(Array.isArray(command)) {
for(var i = 0; i < command.length; i++) {
// debug("========================================================================= command string")
// BinaryParser.ilprint((command.constructor == String) ? command : command.toBinary())
connection.write((command[i].constructor == String) ? command[i] : command[i].toBinary(), "binary");
}
} else {
this.connection.write(command.toBinary(), "binary");
}
// debug("========================================================================= command string")
// BinaryParser.ilprint((command.constructor == String) ? command : command.toBinary())
connection.write((command.constructor == String) ? command : command.toBinary(), "binary");
}
} catch(err) {
// Check if the connection is closed
if(this.connection.readyState != "open" && this.autoReconnect) {
if(connection.readyState != "open" && self.autoReconnect) {
// Add the message to the queue of messages to send
this.messages.push(command);
self.messages.push(command);
// Initiate reconnect if no current running
if(this.connection.currently_reconnecting == null) {
this.connection.currently_reconnecting = true;
// Create the associated connection
var new_connection = net.createConnection(this.port, this.host);
// Set up the net client
new_connection.setEncoding("binary");
new_connection.addListener( "error", function( err ) {
self.emit( "error", err );
self.connection.currently_reconnecting = null;
});
// Add connnect listener
new_connection.addListener("connect", function() {
this.setEncoding("binary");
this.setTimeout(0);
this.setNoDelay();
// Add the listener
this.addListener("data", self.receiveListener);
// assign the new ready connection
self.connection = this;
// send all the messages
if(self.currently_reconnecting == null || self.currently_reconnecting == false) {
self.currently_reconnecting = true;
// Create the pool with connections
self.pool = setupConnectionPool(self, self.poolSize, true);
self.poolByReference = {};
// Save the connections by the fd reference
self.pool.forEach(function(con) {
self.poolByReference[con.connection.fd] = con;
})
// Wait for a reconnect and send all the messages
self.on("reconnect", function() {
self.currently_reconnecting = false;
// Fire the message again
while(self.messages.length > 0) {
var msg = self.messages.shift();
if(msg.constructor == String) {
this.write(msg, "binary");
// Fetch a connection and resend messages
connection = getConnection(self).connection;
// Fetch the a message
var command = self.messages.shift();
// Fire
if(Array.isArray(command)) {
for(var i = 0; i < command.length; i++) {
connection.write((command[i].constructor == String) ? command[i] : command[i].toBinary(), "binary");
}
} else {
this.write(msg.toBinary(), "binary");
}
// this.write(self.messages.shift().toBinary(), "binary");
}
});
connection.write((command.constructor == String) ? command : command.toBinary(), "binary");
}
}
})
}
} else {
// Set connected to false
self.connected = false;
// Throw error
throw err;

@@ -163,2 +281,3 @@ }

};
/**

@@ -168,160 +287,20 @@ * Wrtie command without an attempt of reconnect

*/
Connection.prototype.sendwithoutReconnect = function(command) {
var self = this;
var connection = this.connection;
// Check if the connection is closed
if ( this.connection.readyState != "open" ) {
if (connection.readyState != "open") {
throw new Error( 'Connection closed!' );
}
try {
this.connection.write(command.toBinary(), "binary");
connection.write(command.toBinary(), "binary");
} catch(err) {
// no need to reconnect since called by latest master
// and already went through send() function
throw err;
// no need to reconnect since called by latest master
// and already went through send() function
throw err;
};
};
// Some basic defaults
Connection.DEFAULT_PORT = 27017;
var Server = exports.Server = function(host, port, options) {
this.host = host;
this.port = port;
this.options = options == null ? {} : options;
this.internalConnection;
this.internalMaster = false;
// Setters and getters
this.__defineGetter__("autoReconnect", function() { return this.options['auto_reconnect'] == null ? false : this.options['auto_reconnect']; });
this.__defineGetter__("connection", function() { return this.internalConnection; });
this.__defineSetter__("connection", function(connection) { this.internalConnection = connection; });
this.__defineGetter__("master", function() { return this.internalMaster; });
this.__defineSetter__("master", function(value) { this.internalMaster = value; });
this.__defineGetter__("masterConnection", function() { return this.internalConnection; });
};
Server.prototype.close = function(callback) {
this.connection.close(callback);
};
// Server pair object used to support a failover connection set
var ServerPair = exports.ServerPair = function(leftServer, rightServer) {
if(leftServer == null || rightServer == null || !(leftServer instanceof Server) || !(rightServer instanceof Server)) {
throw Error("Both left/right must be defined and off the type Server");
}
this.leftServer = leftServer;
this.rightServer = rightServer;
// Containst the master server entry
this.master = null;
this.target = null;
// Setters and getters
this.__defineGetter__("autoReconnect", function() {
if(this.target != null) return this.target.autoReconnect;
if(this.masterConnection != null) return this.masterConnection.autoReconnect;
});
this.__defineGetter__("masterConnection", function() {
if(this.target != null && this.target instanceof Server) return this.target.masterConnection;
if(this.leftServer.master) return this.leftServer.masterConnection;
if(this.rightServer.master) return this.rightServer.masterConnection;
return null;
});
};
ServerPair.prototype.setTarget = function(target) {
this.target = target;
this.servers = [];
};
ServerPair.MASTER = 0;
ServerPair.SHADOW_MASTER = 1;
// Server cluster (one master and multiple read slaves)
var ServerCluster = exports.ServerCluster = function(servers) {
// Containst the master server entry
this.master = null;
this.target = null;
if(servers.constructor != Array || servers.length == 0) {
throw Error("The parameter must be an array of servers and contain at least one server");
} else if(servers.constructor == Array || servers.length > 0) {
var count = 0;
servers.forEach(function(server) {
if(server instanceof Server) count = count + 1;
});
if(count < servers.length) {
throw Error("All server entries must be of type Server");
} else {
this.servers = servers;
}
}
// Setters and getters
this.__defineGetter__("autoReconnect", function() {
if(this.target != null) return this.target.autoReconnect;
if(this.masterConnection != null) return this.masterConnection.autoReconnect;
});
this.__defineGetter__("masterConnection", function() {
// Allow overriding to a specific connection
if(this.target != null && this.target instanceof Server) {
return this.target.masterConnection;
} else {
var finalServer = null;
this.servers.forEach(function(server) {
if(server.master == true) finalServer = server;
});
return finalServer != null ? finalServer.masterConnection : finalServer;
}
});
};
ServerCluster.prototype.setTarget = function(target) {
this.target = target;
};
/**
* ReplSetServers constructor provides master-slave functionality
*
* @param serverArr{Array of type Server}
* @return constructor of ServerCluster
*
*/
var ReplSetServers = exports.ReplSetServers = function(servers) {
// Contains the master server entry
this.master = null;
this.target = null;
if(servers.constructor != Array || servers.length == 0) {
throw Error("The parameter must be an array of servers and contain at least one server");
} else if(servers.constructor == Array || servers.length > 0) {
var count = 0;
servers.forEach(function(server) {
if(server instanceof Server) count = count + 1;
});
if(count < servers.length) {
throw Error("All server entries must be of type Server");
} else {
this.servers = servers;
}
}
// Setters and getters
this.__defineGetter__("autoReconnect", function() {
if(this.target != null) return this.target.autoReconnect;
if(this.masterConnection != null) return this.masterConnection.autoReconnect;
});
this.__defineGetter__("masterConnection", function() {
// Allow overriding to a specific connection
if(this.target != null && this.target instanceof Server) {
return this.target.masterConnection;
} else {
var finalServer = null;
this.servers.forEach(function(server) {
if(server.master == true && ( server.connection.connection.readyState == "open") ) finalServer = server;
});
return finalServer != null ? finalServer.masterConnection : finalServer;
}
});
};
ReplSetServers.prototype.setTarget = function(target) {
this.target = target;
};
Connection.DEFAULT_PORT = 27017;
var QueryCommand = require('./commands/query_command').QueryCommand,
GetMoreCommand = require('./commands/get_more_command').GetMoreCommand,
KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand,
Integer = require('./goog/math/integer').Integer,
Long = require('./goog/math/long').Long;
Long = require('./goog/math/long').Long,
debug = require('util').debug,
inspect = require('util').inspect;

@@ -56,3 +57,3 @@ /**

this.batchSizeValue = batchSize == null ? 0 : batchSize;
this.slaveOk = slaveOk == null ? false : slaveOk;
this.slaveOk = slaveOk == null ? collection.slaveOk : slaveOk;

@@ -115,27 +116,23 @@ this.totalNumberOfRecords = 0;

if (!callback) {
if(!callback) {
throw Error('callback is mandatory');
}
try {
if(this.tailable) {
callback(new Error("Tailable cursor cannot be converted to array"), null);
} else if(this.state != Cursor.CLOSED) {
var items = [];
this.each(function(err, item) {
if (item != null) {
items.push(item);
} else {
callback(err, items);
if(this.tailable) {
callback(new Error("Tailable cursor cannot be converted to array"), null);
} else if(this.state != Cursor.CLOSED) {
var items = [];
items = null;
}
this.each(function(err, item) {
if(err != null) return callback(err, null);
item = null;
});
} else {
callback(new Error("Cursor is closed"), null);
}
} catch(err) {
callback(new Error(err.toString()), null);
if (item != null) {
items.push(item);
} else {
callback(err, items);
items = null;
}
});
} else {
callback(new Error("Cursor is closed"), null);
}

@@ -173,2 +170,4 @@ };

self.nextObject(function(err, item) {
if(err != null) return callback(err, null);
if(item != null) {

@@ -178,2 +177,3 @@ callback(null, item);

} else {
// Close the cursor if done
self.state = Cursor.CLOSED;

@@ -238,2 +238,3 @@ callback(err, null);

if(typeof direction === "function") { callback = direction; direction = null; }
if(this.tailable) {

@@ -249,2 +250,3 @@ callback(new Error("Tailable cursor doesn't support sorting"), null);

}
this.sortValue = order;

@@ -270,2 +272,3 @@ callback(null, this);

callback = callback || function(){};
if(this.tailable) {

@@ -283,2 +286,3 @@ callback(new Error("Tailable cursor doesn't support limit"), null);

}
return this;

@@ -301,2 +305,3 @@ };

callback = callback || function(){};
if(this.tailable) {

@@ -314,2 +319,3 @@ callback(new Error("Tailable cursor doesn't support skip"), null);

}
return this;

@@ -332,2 +338,3 @@ };

callback = callback || function(){};
if(this.state == Cursor.CLOSED) {

@@ -356,4 +363,3 @@ callback(new Error("Cursor is closed"), null);

}
}
else {
} else {
requestedLimit = this.batchSizeValue;

@@ -375,13 +381,12 @@ }

if (!this.timeout) {
queryOptions += QueryCommand.OPTS_NO_CURSOR_TIMEOUT;
queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT;
}
if (this.tailable != null) {
queryOptions += QueryCommand.OPTS_TAILABLE_CURSOR;
this.skipValue = this.limitValue = 0;
queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR;
this.skipValue = this.limitValue = 0;
}
if (this.slaveOk) {
queryOptions += QueryCommand.OPTS_SLAVE;
queryOptions |= QueryCommand.OPTS_SLAVE;
}
// limitValue of -1 is a special case used by Db#eval

@@ -467,19 +472,24 @@ var numberToReturn = this.limitValue == -1 ? -1 : this.limitRequest();

var commandHandler = function(err, result) {
if(!err && result.documents[0] && result.documents[0]['$err']) {
self.close(function() {callback(result.documents[0]['$err'], null);});
return;
}
self.queryRun = true;
self.state = Cursor.OPEN; // Adjust the state of the cursor
self.cursorId = result.cursorId;
self.totalNumberOfRecords = result.numberReturned;
// Add the new documents to the list of items
self.items = self.items.concat(result.documents);
self.nextObject(callback);
result = null;
try {
if(err != null && result == null) return callback(err, null);
if(!err && result.documents[0] && result.documents[0]['$err']) {
// Let's keep the cursor open
return self.close(function() {callback(result.documents[0]['$err'], null);});
}
self.queryRun = true;
self.state = Cursor.OPEN; // Adjust the state of the cursor
self.cursorId = result.cursorId;
self.totalNumberOfRecords = result.numberReturned;
// Add the new documents to the list of items
self.items = self.items.concat(result.documents);
self.nextObject(callback);
result = null;
} catch(err) {
callback(new Error(err.toString()), null);
}
};
self.db.executeCommand(self.generateQueryCommand(), commandHandler);
self.db.executeCommand(self.generateQueryCommand(), {read:true}, commandHandler);
commandHandler = null;

@@ -494,3 +504,4 @@ } catch(err) {

} else {
self.close(function() {callback(null, null);});
// Force cursor to stay open
return self.close(function() {callback(null, null);});
}

@@ -521,33 +532,38 @@ }

// Execute the command
self.db.executeCommand(getMoreCommand, function(err, result) {
self.db.executeCommand(getMoreCommand, {read:true}, function(err, result) {
try {
if(err != null) callback(err, null);
self.cursorId = result.cursorId;
self.totalNumberOfRecords += result.numberReturned;
// Determine if there's more documents to fetch
if(result.numberReturned > 0) {
if (self.limitValue > 0) {
var excessResult = self.totalNumberOfRecords - self.limitValue;
self.cursorId = result.cursorId;
self.totalNumberOfRecords += result.numberReturned;
// Determine if there's more documents to fetch
if(result.numberReturned > 0) {
if (self.limitValue > 0) {
var excessResult = self.totalNumberOfRecords - self.limitValue;
if (excessResult > 0) {
result.documents.splice(-1*excessResult, excessResult);
if (excessResult > 0) {
result.documents.splice(-1*excessResult, excessResult);
}
}
self.items = self.items.concat(result.documents);
callback(null, self.items.shift());
} else if(self.tailable) {
self.getMoreTimer = setTimeout(function() {self.getMore(callback);}, 500);
} else {
self.close(function() {callback(null, null);});
}
self.items = self.items.concat(result.documents);
callback(null, self.items.shift());
} else if(self.tailable) {
self.getMoreTimer = setTimeout(function() {self.getMore(callback);}, 500);
} else {
self.close(function() {callback(null, null);});
result = null;
} catch(err) {
callback(new Error(err.toString()), null);
}
result = null;
});
getMoreCommand = null;
getMoreCommand = null;
} catch(err) {
var handleClose = function() {
var handleClose = function() {
callback(new Error(err.toString()), null);
};
self.close(handleClose);

@@ -574,4 +590,6 @@ handleClose = null;

cursor.nextObject(function(err, item) {
if(err != null) return callback(err, null);
// close the cursor
cursor.close(function(err, result) {
if(err != null) return callback(err, null);
callback(null, item);

@@ -599,3 +617,5 @@ });

function execute(command) {
self.db.executeCommand(command, function(err,result) {
self.db.executeCommand(command, {read:true}, function(err,result) {
if(err != null) return callback(err, null);
if (!self.queryRun && result) {

@@ -607,2 +627,3 @@ self.queryRun = true;

}
if (result.documents && result.documents.length) {

@@ -634,2 +655,3 @@ try {

}
return stream;

@@ -652,3 +674,3 @@ };

var command = new KillCursorCommand(this.db, [this.cursorId]);
this.db.executeCommand(command, null);
this.db.executeCommand(command, {read:true}, null);
} catch(err) {}

@@ -658,6 +680,6 @@ }

this.cursorId = self.db.bson_serializer.Long.fromInt(0);
this.state = Cursor.CLOSED;
this.state = Cursor.CLOSED;
// callback for backward compatibility
if (callback) {
if(callback) {
callback(null, this);

@@ -664,0 +686,0 @@ } else {

@@ -8,11 +8,10 @@ var QueryCommand = require('./commands/query_command').QueryCommand,

Collection = require('./collection').Collection,
Server = require('./connection').Server,
ServerPair = require('./connection').ServerPair,
ServerCluster = require('./connection').ServerCluster,
ReplSetServers = require('./connection').ReplSetServers,
Server = require('./connections/server').Server,
ReplSetServers = require('./connections/repl_set_servers').ReplSetServers,
Cursor = require('./cursor').Cursor,
MD5 = require('./crypto/md5').MD5,
EventEmitter = require('events').EventEmitter,
inherits = require('sys').inherits,
sys = require('sys');
inherits = require('util').inherits,
debug = require('util').debug,
inspect = require('util').inspect;

@@ -23,20 +22,24 @@ var Db = exports.Db = function(databaseName, serverConfig, options) {

this.serverConfig = serverConfig;
this.options = options == null ? {} : options;
this.options = options == null ? {} : options;
// Contains all the connections for the db
try {
this.bson_serializer = this.options.native_parser ? require('../../external-libs/bson/bson') : require('./bson/bson');
this.bson_deserializer = this.options.native_parser ? require('../../external-libs/bson/bson') : require('./bson/bson');
var serializer = this.options.native_parser ? require('../../external-libs/bson') : require('./bson/bson');
this.bson_serializer = serializer;
this.bson_deserializer = serializer;
} catch (err) {
// If we tried to instantiate the native driver
throw "Native bson parser not compiled, please compile or avoud using native_parser=true";
throw "Native bson parser not compiled, please compile or avoid using native_parser=true";
}
this.connections = [];
// State of the db connection
this.state = 'notConnected';
this.pkFactory = this.options.pk == null ? this.bson_serializer.ObjectID : this.options.pk;
this.forceServerObjectId = this.options.forceServerObjectId != null ? this.options.forceServerObjectId : false;
// Added strict
this.strict = this.options.strict == null ? false : this.options.strict;
this.notReplied ={};
this.slaveOk = false;
this.isInitializing = true;
this.auths = [];
};

@@ -50,255 +53,31 @@

// Set up connections
if(self.serverConfig instanceof Server) {
self.serverConfig.connection = new Connection(self.serverConfig.host, self.serverConfig.port, self.serverConfig.autoReconnect);
self.connections.push(self.serverConfig.connection);
var server = self.serverConfig;
self.serverConfig.connection.addListener("connect", function() {
// Create a callback function for a given connection
var connectCallback = function(err, reply) {
if(err != null) {
return callback(err, null);
} else if(reply.documents[0].ismaster == 1) {
self.serverConfig.master = true;
} else if(reply.documents[0].ismaster == 0) {
self.serverConfig.master = false;
}
// emit a message saying we got a master and are ready to go and change state to reflect it
if(self.state == 'notConnected') {
self.state = 'connected';
//
// Call the server version function via admin to adapt to changes from 1.7.6 >
self.admin(function(err, admindb) {
admindb.serverInfo(function(err, doc) {
if(err != null) return callback(err, null);
// Store the db version
self.version = doc.version;
callback(null, self);
});
});
} else {
callback("connection already opened");
}
};
// Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
var db_command = DbCommand.createIsMasterCommand(self);
self.addListener(db_command.getRequestId().toString(), connectCallback);
self.notReplied[db_command.getRequestId().toString()] = this;
// Let's send a request to identify the state of the server
this.send(db_command);
});
self.serverConfig.connection.addListener("data", function(message) {
// Parse the data as a reply object
var reply = new MongoReply(self, message);
// Emit message
self.emit(reply.responseTo.toString(), null, reply);
// Remove the listener
if ( self.notReplied[ reply.responseTo.toString()]) {
delete self.notReplied[ reply.responseTo.toString()];
self.removeListener(reply.responseTo.toString(), self.listeners( reply.responseTo.toString())[0] );
}
});
if(self.serverConfig instanceof Server || self.serverConfig instanceof ReplSetServers) {
// Inner function for authentication
var authenticateFunction = function(self, username, password) {
return function() {
self.authenticate(username, password, function(err, result) {
// Just ignore the result for now
});
}
}
self.serverConfig.connection.addListener("error", function(err) {
if(self.listeners("error") != null && self.listeners("error").length > 0) self.emit("error", err);
self.state = "notConnected"
return callback(err, null);
});
// Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event)
self.serverConfig.connection.addListener("timeout", function() { self.emit("timeout", this); });
self.serverConfig.connection.addListener("close", function() { self.emit("close", this); });
// Open the connection
self.serverConfig.connection.open();
} else if(self.serverConfig instanceof ServerPair || self.serverConfig instanceof ServerCluster) {
var serverConnections = self.serverConfig instanceof ServerPair ? [self.serverConfig.leftServer, self.serverConfig.rightServer] : self.serverConfig.servers;
var numberOfCheckedServers = 0;
serverConnections.forEach(function(server) {
server.connection = new Connection(server.host, server.port, server.autoReconnect);
self.connections.push(server.connection);
var handleServerConnection = function() {
numberOfCheckedServers+=1;
if(numberOfCheckedServers == serverConnections.length) {
if(self.masterConnection) {
// emit a message saying we got a master and are ready to go and change state to reflect it
self.state = 'connected';
callback(null, self);
} else {
// emit error only when all servers are checked and connecting to them failed.
self.state = "notConnected"
callback(new Error("Failed connecting to any of the servers in the cluster"), null);
}
// Add a listener for the reconnect event
self.on("reconnect", function() {
// Number of current auths
var authLength = self.auths.length;
// // If we have any auths fire off the auth message to all the connections
if(self.auths.length > 0) {
for(var i = 0; i < authLength; i++) {
authenticateFunction(self, self.auths[i].username, self.auths[i].password)();
}
}
});
server.connection.addListener("connect", function() {
// Create a callback function for a given connection
var connectCallback = function(err, reply) {
if(err != null) {
callback(err, null);
} else {
if(reply.documents[0].ismaster == 1) {
// Locate the master connection and save it
self.masterConnection = server.connection;
server.master = true;
} else {
server.master = false;
}
handleServerConnection();
}
};
// Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
var db_command = DbCommand.createIsMasterCommand(self);
self.addListener(db_command.getRequestId().toString(), connectCallback);
// Let's send a request to identify the state of the server
this.send(db_command);
});
server.connection.addListener("data", function(message) {
// Parse the data as a reply object
var reply = new MongoReply(self, message);
// Emit error if there is one
reply.responseHasError ? self.emit(reply.responseTo.toString(), reply.documents[0], reply) : self.emit(reply.responseTo.toString(), null, reply);
// Remove the listener
self.removeListener(reply.responseTo.toString(), self.listeners(reply.responseTo.toString())[0]);
});
server.connection.addListener("error", function(err) {
handleServerConnection();
});
// Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event)
server.connection.addListener("timeout", function() { self.emit("timeout", this); });
server.connection.addListener("close", function() { self.emit("close", this); });
// Open the connection
server.connection.open();
self.serverConfig.connect(self, function(err, result) {
if(err != null) return callback(err, null);
// Callback
return callback(null, self);
});
} else if ( self.serverConfig instanceof ReplSetServers ) {
var serverConnections = self.serverConfig instanceof ServerPair ? [self.serverConfig.leftServer, self.serverConfig.rightServer] : self.serverConfig.servers;
var numberOfConnectedServers = 0;
var numberOfErrorServers = 0;
self.serverConfig.addresses = {};
var initServer = function(server) {
self.serverConfig.addresses[ server.host + ':' + server.port ] = 1;
server.connection = new Connection(server.host, server.port, server.autoReconnect);
//console.log( 'Connect to ' + server.host + ':' + server.port );
self.connections.push(server.connection);
server.connection.addListener("connect", function() {
// Create a callback function for a given connection
var connectCallback = function(err, reply) {
if(err != null) {
callback(err, null);
} else {
if(reply.documents[0].ismaster == 1) {
// Locate the master connection and save it
self.masterConnection = server.connection;
server.master = true;
} else {
server.master = false;
}
if ( self.serverConfig instanceof ReplSetServers && ( reply.documents[0].hosts != undefined ) ) {
var replicas = reply.documents[0].hosts;
for( var i in replicas ) {
if ( replicas[i] in self.serverConfig.addresses )
continue;
self.serverConfig.addresses[ replicas[i] ] = 1;
var ipAndPort = replicas[i].split(":");
var newServer = new Server( ipAndPort[0], parseInt( ipAndPort[1]), { auto_reconnect: true} );
console.log( 'Added ' + replicas[i] + ' to the replica set' );
serverConnections.push( newServer );
initServer( newServer );
}
}
// emit a message saying we got a master and are ready to go and change state to reflect it
if(++numberOfConnectedServers == serverConnections.length && (self.state == 'notConnected')) {
self.state = 'connected';
self.isInitializing = false;
return callback(null, self);
}
if ( self.serverConfig instanceof ReplSetServers && server.master ) {
//we have the master we are ok, wait for others (if any) to connect too
self.state = 'connected';
}
if ( self.serverConfig instanceof ReplSetServers && ( (numberOfConnectedServers + numberOfErrorServers ) == serverConnections.length )) {
self.isInitializing = false;
if ( self.state == 'connected' ) {
return callback( null, self );
} else {
return callback( new Error( 'No master available'), null );
}
}
}
};
// Create db command and Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
var db_command = DbCommand.createIsMasterCommand(self);
self.addListener(db_command.getRequestId().toString(), connectCallback);
self.notReplied[db_command.getRequestId().toString()] = this;
// Let's send a request to identify the state of the server
this.send(db_command);
server.connection.addListener("data", function(message) {
// Parse the data as a reply object
var reply = new MongoReply(self, message);
// Emit error if there is one
reply.responseHasError ? self.emit(reply.responseTo.toString(), reply.documents[0], reply) : self.emit(reply.responseTo.toString(), null, reply);
// Remove the listener
//if ( self.listeners(reply.responseTo.toString()).length )
if ( self.notReplied [ reply.responseTo.toString()] ) {
delete self.notReplied[ reply.responseTo.toString()];
self.removeListener(reply.responseTo.toString(), self.listeners(reply.responseTo.toString())[0]);
}
});
});
server.connection.addListener("error", function(err) {
if ( self.serverConfig instanceof ReplSetServers && self.isInitializing) {
//we only have one error, if the rest are ok there is no problem
numberOfErrorServers++;
//console.log( server.host + ':' + server.port + ' down!!!'+ err );
if ( (numberOfErrorServers + numberOfConnectedServers) == serverConnections.length) {
self.isInitializing = false;
if ( self.state == 'connected' ) {
return callback( null, self );
} else {
return callback( new Error( 'No master available'), null );
}
}
} else if ( self.serverConfig instanceof ReplSetServers ) {
for ( var i in self.notReplied ) {
//console.log( 'delete event ' + i );
if ( self.notReplied[i] == this ) {
delete self.notReplied[i];
self.emit( i, null, { documents: [{'$err':'Connection closed'}] } );
self.removeListener( i, self.listeners( i )[0]);
}
}
} else {
return callback(err, null);
}
});
// Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event)
server.connection.addListener("timeout", function() { self.emit("timeout", this); });
server.connection.addListener("close", function() { self.emit("close", this); });
// Open the connection
server.connection.open();
};
serverConnections.forEach( initServer );
} else {
return callback(Error("Server parameter must be of type Server, ServerPair, ServerCluster or ReplSetServers"), null);
return callback(Error("Server parameter must be of type Server or ReplSetServers"), null);
}

@@ -308,5 +87,6 @@ };

Db.prototype.close = function() {
this.connections.forEach(function(connection) {
connection.close();
});
// Remove all listeners
this.removeAllListeners("reconnect");
// Close connection
this.serverConfig.close();
// Clear out state of the connection

@@ -317,2 +97,3 @@ this.state = "notConnected"

Db.prototype.admin = function(callback) {
if(callback == null) return new Admin(this);
callback(null, new Admin(this));

@@ -348,3 +129,7 @@ };

self.collectionsInfo(collection_name, function(err, cursor) {
if(err != null) return callback(err, null);
cursor.toArray(function(err, documents) {
if(err != null) return callback(err, null);
// List of result documents that have been filtered

@@ -366,16 +151,19 @@ var filtered_documents = [];

**/
Db.prototype.collection = function(collectionName, callback) {
Db.prototype.collection = function(collectionName, options, callback) {
var self = this;
if(typeof options === "function") { callback = options; options = {}; }
try {
if(self.strict) {
if(options && options.safe || this.strict) {
self.collectionNames(collectionName, function(err, collections) {
if(err != null) return callback(err, null);
if(collections.length == 0) {
callback(new Error("Collection " + collectionName + " does not exist. Currently in strict mode."), null);
return callback(new Error("Collection " + collectionName + " does not exist. Currently in strict mode."), null);
} else {
return callback(null, new Collection(self, collectionName, self.pkFactory));
return callback(null, new Collection(self, collectionName, self.pkFactory, options));
}
});
} else {
return callback(null, new Collection(self, collectionName, self.pkFactory));
return callback(null, new Collection(self, collectionName, self.pkFactory, options));
}

@@ -394,5 +182,6 @@ } catch(err) {

self.collectionNames(function(err, documents) {
if(err != null) return callback(err, null);
var collections = [];
documents.forEach(function(document) {
collections.push(new Collection(self, document.name.replace(self.databaseName + ".", '')));
collections.push(new Collection(self, document.name.replace(self.databaseName + ".", ''), self.pkFactory));
});

@@ -426,2 +215,4 @@ // Return the collection objects

new Cursor(this, new Collection(this, DbCommand.SYSTEM_COMMAND_COLLECTION), selector, {}, 0, -1).nextObject(function(err, result) {
if(err != null) return callback(err, null);
if(result.ok == 1) {

@@ -437,2 +228,4 @@ callback(null, result.retval);

this.collection(dbRef.namespace, function(err, collection) {
if(err != null) return callback(err, null);
collection.findOne({'_id':dbRef.oid}, function(err, result) {

@@ -449,19 +242,45 @@ callback(err, result);

var self = this;
// Execute command
this.executeCommand(DbCommand.createGetNonceCommand(self), function(err, reply) {
if(err == null) {
// Nonce used to make authentication request with md5 hash
var nonce = reply.documents[0].nonce;
// Execute command
self.executeCommand(DbCommand.createAuthenticationCommand(self, username, password, nonce), function(err, result) {
if(err == null && result.documents[0].ok == 1) {
callback(null, true);
// Add the auth details to the connection for reconnects or update existing if any
var found = false;
for(var i = 0; i < self.auths.length; i++) {
// If we have found an existing auth, update the password
if(self.auths[i].username == username) {
found = true;
self.auths[i].password = password;
}
}
// Push the new auth if we have no previous record
if(!found) self.auths.push({'username':username, 'password':password});
// Figure out the number of times we need to trigger
var rawConnections = self.serverConfig.allRawConnections();
var numberOfExpectedReturns = rawConnections.length;
// Execute the commands
for(var i = 0; i < numberOfExpectedReturns; i++) {
// Execute command
var createNonceCallback = function(index) {
return function(err, reply) {
if(err == null) {
// Nonce used to make authentication request with md5 hash
var nonce = reply.documents[0].nonce;
// Execute command
self.executeCommand(DbCommand.createAuthenticationCommand(self, username, password, nonce), {writer: rawConnections[index].connection}, function(err, result) {
// Ajust the number of expected results
numberOfExpectedReturns = numberOfExpectedReturns - 1;
// If we are done let's evaluate
if(numberOfExpectedReturns <= 0) {
if(err == null && result.documents[0].ok == 1) {
callback(null, true);
} else {
err != null ? callback(err, false) : callback(new Error(result.documents[0].errmsg), false);
}
}
});
} else {
err != null ? callback(err, false) : callback(new Error(result.documents[0].errmsg), false);
callback(err, null);
}
});
} else {
callback(err, null);
}
}
});
this.executeCommand(DbCommand.createGetNonceCommand(self), {writer: rawConnections[i].connection}, createNonceCallback(i));
}
};

@@ -477,3 +296,3 @@

// Insert the user into the system users collections
collection.insert({user: username, pwd: userPassword}, function(err, documents) {
collection.insert({user: username, pwd: userPassword}, {safe:true}, function(err, documents) {
callback(err, documents);

@@ -516,6 +335,7 @@ });

options = args.length ? args.shift() : null;
var self = this;
// Check if we have the name
this.collectionNames(collectionName, function(err, collections) {
if(err != null) return callback(err, null);
var found = false;

@@ -534,3 +354,3 @@ collections.forEach(function(collection) {

// Create a new collection and return it
self.executeCommand(DbCommand.createCreateCollectionCommand(self, collectionName, options), function(err, result) {
self.executeCommand(DbCommand.createCreateCollectionCommand(self, collectionName, options), {read:false, safe:true}, function(err, result) {
if(err == null && result.documents[0].ok == 1) {

@@ -573,10 +393,12 @@ callback(null, new Collection(self, collectionName, self.pkFactory));

**/
Db.prototype.lastError = function(callback) {
this.executeCommand(DbCommand.createGetLastErrorCommand(this), function(err, error) {
callback(err, error.documents);
Db.prototype.lastError = function(options, callback) {
if ('function' === typeof options) callback = options, options = {};
this.executeCommand(DbCommand.createGetLastErrorCommand(options, this), function(err, error) {
callback(err, error && error.documents);
});
};
Db.prototype.error = function(callback) {
this.lastError(callback);
Db.prototype.error = function(options, callback) {
this.lastError(options, callback);
};

@@ -608,2 +430,9 @@

/**
Runs a command on the database as admin
**/
Db.prototype.executeDbAdminCommand = function(command_hash, callback) {
this.executeCommand(DbCommand.createAdminDbCommand(this, command_hash), callback);
};
/**
Resets the error history of the mongo instance

@@ -618,7 +447,15 @@ **/

**/
Db.prototype.createIndex = function(collectionName, fieldOrSpec, unique, callback) {
if(callback == null) { callback = unique; unique = null; }
var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, unique);
this.executeCommand(command, function(result) {});
callback(null, command.documents[0].name);
Db.prototype.createIndex = function(collectionName, fieldOrSpec, options, callback) {
if(callback == null) { callback = options; options = null; }
var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options);
this.executeCommand(command, {read:false, safe:true}, function(err, result) {
if(err != null) return callback(err, null);
result = result && result.documents;
if (result[0].err) {
callback(new Error(result[0].err));
} else {
callback(null, command.documents[0].name);
}
});
};

@@ -629,5 +466,5 @@

**/
Db.prototype.ensureIndex = function(collectionName, fieldOrSpec, unique, callback) {
if(callback == null) { callback = unique; unique = null; }
var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, unique);
Db.prototype.ensureIndex = function(collectionName, fieldOrSpec, options, callback) {
if(callback == null) { callback = options; options = null; }
var command = DbCommand.createCreateIndexCommand(this, collectionName, fieldOrSpec, options);
var index_name = command.documents[0].name;

@@ -637,4 +474,16 @@ var self = this;

this.indexInformation(collectionName, function(err, collectionInfo) {
if(!collectionInfo[index_name]) self.executeCommand(command, function(result) {});
return callback(null, index_name);
if(!collectionInfo[index_name]) {
self.executeCommand(command, {read:false, safe:true}, function(err, result) {
if(err != null) return callback(err, null);
result = result && result.documents;
if (result[0].err) {
callback(new Error(result[0].err));
} else {
callback(null, command.documents[0].name);
}
});
} else {
return callback(null, index_name);
}
});

@@ -669,2 +518,4 @@ };

new Cursor(this, new Collection(this, DbCommand.SYSTEM_INDEX_COLLECTION), selector).each(function(err, index) {
if(err != null) return callback(err, null);
// Return the info when finished

@@ -694,45 +545,110 @@ if(index == null) {

**/
Db.prototype.executeCommand = function(db_command, callback) {
Db.prototype.executeCommand = function(db_command, options, callback) {
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
callback = args.pop();
options = args.length ? args.shift() : {};
// Options unpacking
var read = options['read'] != null ? options['read'] : false;
var safe = options['safe'] != null ? options['safe'] : false;
// Let's us pass in a writer to force the use of a connection (used for admin where we need to peform 2 calls against the same connection)
var rawConnection = options['writer'] != null ? options['writer'] : null;
// debug("===================================================== executeCommnad")
// debug(" read :: " + read)
// debug(" safe :: " + safe)
// debug(" writer :: " + writer)
var errorCommand = null;
if(safe == true) {
errorCommand = DbCommand.createGetLastErrorCommand(safe, this);
}
// If we have a callback execute
if(callback instanceof Function) {
var listenToCommand = errorCommand != null ? errorCommand : db_command;
// Add the callback to the list of callbacks by the request id (mapping outgoing messages to correct callbacks)
this.addListener(db_command.getRequestId().toString(), callback);
if ( self.serverConfig.masterConnection != null ) {
this.notReplied[db_command.getRequestId().toString()] = self.serverConfig.masterConnection;
}
this.on(listenToCommand.getRequestId().toString(), callback);
if(self.serverConfig.primary != null) {
this.notReplied[listenToCommand.getRequestId().toString()] = self.serverConfig.primary;
}
}
// Correctly handle serialization errors
var checkMasterHandler = function(err, reply, dbinstance){
if (err == null){
try{
if ( dbinstance.backup.server ) { // use slave this ONE time
self.notReplied[db_command.getRequestId().toString()] = dbinstance.backup.server.connection;
dbinstance.backup.server.connection.send( db_command);
dbinstance.backup.server = null;
} else {
self.notReplied[db_command.getRequestId().toString()] = dbinstance.serverConfig.masterConnection;
dbinstance.serverConfig.masterConnection.send(db_command);
}
} catch ( err ) {
// Clean up callback if it exists
if(this.notReplied[db_command.getRequestId().toString()] != null) {
delete self.notReplied[db_command.getRequestId().toString()];
}
if(callback instanceof Function) {
return callback(err, null);
}
try{
// Attempt forcing a reconnect if we have a replicaset server
if(self.serverConfig instanceof ReplSetServers && !self.serverConfig.isConnected()) {
// Initialize
self.isInitializing = true;
// Number of retries
var retries = self.serverConfig.retries;
// Attempts a reconnect
var reconnectAttempt = function() {
// Try reconnect
self.serverConfig.connect(self, function(err, result) {
// debug("============================================================ reconnectAttemp")
// debug("err :: " + inspect(err))
// Initialize
self.isInitializing = true;
// Set retries
retries = retries - 1;
// If we fail retry the connec
if(err != null && retries > 0) {
// Wait an try again
setTimeout(reconnectAttempt, self.serverConfig.reconnectWait);
} else {
// Ensure we catch any errors happening and report them (especially important for replicaset servers)
try {
if(err != null && callback instanceof Function) return callback(err, null);
// for the other instances fire the message
// debug("=========================== attempt read :: 2 :: " + read)
var writer = read ? self.serverConfig.checkoutReader() : self.serverConfig.checkoutWriter();
// If we got safe set
if(errorCommand != null) {
writer.send([db_command, errorCommand], rawConnection);
} else {
writer.send(db_command, rawConnection)
}
} catch (err) {
// Set server config to disconnected if it's a replicaset
if(self.serverConfig instanceof ReplSetServers && err == "notConnected") {
// Just clear up all connections as we need to perform a complete reconnect for the call
self.serverConfig.disconnect();
}
// Signal an error
if(!(err instanceof Error)) err = new Error(err);
if(callback instanceof Function) {
if(errorCommand != null) delete self.notReplied[errorCommand.getRequestId().toString()];
return callback(err, null);
}
}
}
});
}
// Force a reconnect after self.serverConfig.reconnectWait seconds
setTimeout(reconnectAttempt, self.serverConfig.reconnectWait);
} else {
// for the other instances fire the message
var writer = read ? self.serverConfig.checkoutReader() : self.serverConfig.checkoutWriter();
// If we got safe set
if(errorCommand != null) {
writer.send([db_command, errorCommand], rawConnection);
} else {
writer.send(db_command, rawConnection)
}
} else {
// XXX : LOOP!!!!!!
setTimeout( self.checkMaster_(self, checkMasterHandler), 50 );
}
} catch(err){
// Set server config to disconnected if it's a replicaset
if(self.serverConfig instanceof ReplSetServers && err == "notConnected") {
// Just clear up all connections as we need to perform a complete reconnect for the call
self.serverConfig.disconnect();
}
};
try{
self.serverConfig.masterConnection.send(db_command);
} catch(err){
if(callback instanceof Function) {
delete self.notReplied[db_command.getRequestId().toString()];
// Signal an error
if(!(err instanceof Error)) err = new Error(err);
if(callback instanceof Function) {
if(errorCommand != null) delete self.notReplied[errorCommand.getRequestId().toString()];
return callback(err, null);

@@ -742,3 +658,3 @@ }

// Return error object
return err;
return err;
}

@@ -782,120 +698,1 @@ };

}
/**
* Checks for latest master by calling isMasterCommand on each server
* of serverConfig
* @param dbcopy{instance of db}
*
**/
Db.prototype.checkMaster_ = function(dbcopy, returnback) {
var self = dbcopy;
var hasReturned = false;
var answers = 0;
dbcopy.backup = {};
var servers = dbcopy.serverConfig.servers;
if(Array.isArray(servers)) {
for(var serveri = 0; serveri < servers.length; serveri++) {
var server = servers[serveri];
server.master = false;
if(server.connection.connection.readyState == "open" || server.connection.autoReconnect) {
var db_cmnd = DbCommand.createIsMasterCommand(dbcopy);
var connect_Callback = function(err, reply) {
if(err != null) {
if (!hasReturned && ( ++answers == dbcopy.serverConfig.servers.length)) {
if (dbcopy.backup.server && dbcopy.backup.reply) {
dbcopy.masterConnection = dbcopy.backup.server.connection;
return returnback( null, dbcopy.backup.reply, dbcopy );
} else {
return returnback( new Error( 'No master found' ) );
}
}
} else {
if(reply.documents[0].ismaster == 1) {
// Locate the master connection and save it
dbcopy.masterConnection = server.connection;
server.master = true;
hasReturned = true;
return returnback(null, reply, dbcopy);
} else {
server.master = false;
// we may not have a master so we keep a secondary server,
// that is able to respond, just in case
dbcopy.backup.server = server;
dbcopy.backup.reply = reply;
if ( !hasReturned && ( ++answers == dbcopy.serverConfig.servers.length )) {
if ( dbcopy.backup.server && dbcopy.backup.reply ) {
dbcopy.masterConnection = dbcopy.backup.server.connection;
return returnback( null, dbcopy.backup.reply, dbcopy );
} else {
return returnback(new Error( 'No master found' ));
}
}
}
}
}
dbcopy.addListener(db_cmnd.getRequestId().toString(), connect_Callback);
self.notReplied[db_cmnd.getRequestId().toString()] = server.connection;
if(server.connection.connection.readyState == "open") {
server.connection.sendwithoutReconnect(db_cmnd);
} else {
// This if it's closed it may not have a listener
// The listener is of general use so we need not use one for every command
if (!server.connection.listeners("data").length) {
server.connection.addListener("data", function(message) {
// Parse the data as a reply object
var reply = null;
if ( message ) {
reply = new MongoReply(self, message);
} else {
reply = {};
reply.responseHasError = true;
reply.documents = ['Error connecting'];
}
// Emit error if there is one
reply.responseHasError ? self.emit(reply.responseTo.toString(), reply.documents[0], reply) : self.emit(reply.responseTo.toString(), null, reply);
// Remove the listener
if(self.notReplied[ reply.responseTo.toString()]) {
delete self.notReplied[ reply.responseTo.toString()];
self.removeListener(reply.responseTo.toString(), self.listeners( reply.responseTo.toString())[0]);
}
});
}
if (server.connection.listeners("error").length == 0) {
server.connection.addListener("error", function(err) {
dbcopy.emit("error", err);
server.master = false;
});
}
// Emit timeout and close events so the client using db can figure do proper error handling (emit contains the connection that triggered the event)
if (server.connection.listeners("timeout").length == 0) {
server.connection.addListener("timeout", function() { dbcopy.emit("timeout", this); });
}
if (server.connection.listeners("close").length == 0) {
server.connection.addListener("close", function() { dbcopy.emit("close", this); });
}
server.connection.send(db_cmnd);
}
} else {
server.master = false;
if (!hasReturned && ( ++answers == dbcopy.serverConfig.servers.length)) {
if (dbcopy.backup.server && dbcopy.backup.reply) {
dbcopy.masterConnection = dbcopy.backup.server.connection;
return returnback( null, dbcopy.backup.reply, dbcopy );
} else {
return returnback( new Error( 'No master found' ) );
}
}
}
}
}
}
var BinaryParser = require('../bson/binary_parser').BinaryParser,
sys = require('sys');
sys = require('util'),
debug = require('util').debug,
inspect = require('util').inspect;

@@ -61,3 +63,4 @@ /**

Chunk.prototype.write = function(data, callback) {
this.data.write(data.toString('binary'), this.internalPosition);
// this.data.write(data.toString('binary'), this.internalPosition);
this.data.write(data, this.internalPosition);
this.internalPosition = this.data.length();

@@ -92,4 +95,4 @@ callback(null, this);

data = new Buffer(length);
//todo there is performance degradation! we need direct Binary::write() into buffer with offset support!
length = data.write(this.data.read(this.internalPosition, length), 'binary', 0);
//length = data.write(this.data.read(this.internalPosition, length), 'binary', 0);
length = this.data.readInto(data, this.internalPosition);
}

@@ -145,6 +148,7 @@ this.internalPosition = this.internalPosition + length;

self.file.chunkCollection(function(err, collection) {
collection.remove({'_id':self.objectId}, function(err, collection) {
collection.remove({'_id':self.objectId}, {safe:true}, function(err, result) {
if(self.data.length() > 0) {
self.buildMongoObject(function(mongoObject) {
collection.insert(mongoObject, function(collection) {
collection.insert(mongoObject, {safe:true}, function(err, collection) {
callback(null, self);

@@ -151,0 +155,0 @@ });

@@ -13,10 +13,9 @@ /**

DbCommand = require('../commands/db_command').DbCommand,
Integer = require('../goog/math/integer').Integer,
// ObjectID = require('../bson/bson').ObjectID,
Buffer = require('buffer').Buffer,
fs = require('fs'),
util = require('util'),
debug = require('util').debug,
inspect = require('util').inspect,
Stream = require('stream').Stream;
/**

@@ -96,3 +95,26 @@ * A class representation of a file stored in GridFS.

var self = this;
if((self.mode == "w" || self.mode == "w+") && self.db.serverConfig.primary != null) {
// Get files collection
self.collection(function(err, collection) {
// Ensure index on files Collection
collection.ensureIndex([['filename', 1], ['uploadDate', -1]], function(err, index) {
// Get chunk collection
self.chunkCollection(function(err, chunkCollection) {
// Ensure index on chunk collection
chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
self._open(callback);
});
});
});
});
} else {
self._open(callback);
}
}
GridStore.prototype._open = function(callback) {
var self = this;
self.collection(function(err, collection) {

@@ -127,5 +149,17 @@ if(err!==null) {

if(self.mode == "r") {
chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
self.nthChunk(0, function(err, chunk) {
self.currentChunk = chunk;
// chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
self.nthChunk(0, function(err, chunk) {
self.currentChunk = chunk;
self.position = 0;
callback(null, self);
});
// });
} else if(self.mode == "w") {
self.chunkCollection(function(err, collection2) {
// Delete any existing chunks
self.deleteChunks(function(err, result) {
self.currentChunk = new Chunk(self, {'n':0});
self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type'];
self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
self.position = 0;

@@ -135,31 +169,13 @@ callback(null, self);

});
} else if(self.mode == "w") {
self.chunkCollection(function(err, collection2) {
// Create index for the chunks
//chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
// Delete any existing chunks
self.deleteChunks(function(err, result) {
self.currentChunk = new Chunk(self, {'n':0});
self.contentType = self.options['content_type'] == null ? self.contentType : self.options['content_type'];
self.internalChunkSize = self.options['chunk_size'] == null ? self.internalChunkSize : self.options['chunk_size'];
self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
self.position = 0;
callback(null, self);
});
//});
});
} else if(self.mode == "w+") {
self.chunkCollection(function(err, collection) {
// Create index for the chunks
//chunkCollection.ensureIndex([['files_id', 1], ['n', 1]], function(err, index) {
self.nthChunk(self.lastChunkNumber(), function(err, chunk) {
// Set the current chunk
self.currentChunk = chunk == null ? new Chunk(self, {'n':0}) : chunk;
self.currentChunk.position = self.currentChunk.data.length();
self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
self.position = self.length;
callback(null, self);
});
//});
});
self.nthChunk(self.lastChunkNumber(), function(err, chunk) {
// Set the current chunk
self.currentChunk = chunk == null ? new Chunk(self, {'n':0}) : chunk;
self.currentChunk.position = self.currentChunk.data.length();
self.metadata = self.options['metadata'] == null ? self.metadata : self.options['metadata'];
self.position = self.length;
callback(null, self);
});
});
} else {

@@ -196,22 +212,56 @@ callback(new Error("Illegal mode " + self.mode), null);

fs.fstat(file, function (err, stats) {
var startIndices = [];
for (var i = 0; i < stats.size; i += self.chunkSize) startIndices.push(i);
startIndices.forEach(function (start, index, startIndices) {
process.nextTick(function () {
fs.read(file, self.chunkSize, start, 'binary', function (err, data, bytesRead) {
var chunk = new Chunk(self, {n: index});
chunk.write(data, function (err, chunk) {
chunk.save(function (err, result) {
if (index == startIndices.length -1) {
self.currentChunk = chunk;
self.close(function (err, result) {
callback(null, self);
});
}
});
var offset = 0;
var index = 0;
var numberOfChunksLeft = Math.min(stats.size / self.chunkSize);
// Write a chunk
var writeChunk = function() {
fs.read(file, self.chunkSize, offset, 'binary', function(err, data, bytesRead) {
offset = offset + bytesRead;
// Create a new chunk for the data
var chunk = new Chunk(self, {n:index++});
chunk.write(data, function(err, chunk) {
chunk.save(function(err, result) {
// Point to current chunk
self.currentChunk = chunk;
// debug("=========================== err :: " + err)
// debug("=========================== err :: " + inspect(result))
// debug("============================= offset :: " + offset)
if(offset >= stats.size) {
fs.close(file);
self.close(function(err, result) {
return callback(null, self);
})
} else {
return process.nextTick(writeChunk);
}
});
});
});
});
}
// Process the first write
process.nextTick(writeChunk);
// var startIndices = [];
// for (var i = 0; i < stats.size; i += self.chunkSize) startIndices.push(i);
//
// startIndices.forEach(function (start, index, startIndices) {
// process.nextTick(function () {
// fs.read(file, self.chunkSize, start, 'binary', function (err, data, bytesRead) {
// var chunk = new Chunk(self, {n: index});
// chunk.write(data, function (err, chunk) {
// chunk.save(function (err, result) {
// if (index == startIndices.length -1) {
// self.currentChunk = chunk;
// self.close(function (err, result) {
// callback(null, self);
// });
// }
// });
// });
// });
// });
// });
});

@@ -245,4 +295,2 @@ });

if((self.currentChunk.position + string.length) > self.chunkSize) {
// sys.puts("==============================================================1")
var previousChunkNumber = self.currentChunk.chunkNumber;

@@ -400,5 +448,5 @@ var leftOverDataSize = self.chunkSize - self.currentChunk.position;

if(self.uploadDate != null) {
files.remove({'_id':self.fileId}, function(err, collection) {
files.remove({'_id':self.fileId}, {safe:true}, function(err, collection) {
self.buildMongoObject(function(mongoObject) {
files.save(mongoObject, function(err, doc) {
files.save(mongoObject, {safe:true}, function(err, doc) {
callback(err, doc);

@@ -411,3 +459,3 @@ });

self.buildMongoObject(function(mongoObject) {
files.save( mongoObject, function(err, doc) {
files.save(mongoObject, {safe:true}, function(err, doc) {
callback(err, doc);

@@ -423,3 +471,3 @@ });

self.buildMongoObject(function(mongoObject) {
files.save(mongoObject, function(err, doc) {
files.save(mongoObject, {safe:true}, function(err, doc) {
callback(err, doc);

@@ -430,2 +478,4 @@ });

}
} else if(self.mode[0] == "r") {
callback(null, null);
} else {

@@ -501,3 +551,3 @@ callback(new Error("Illegal mode " + self.mode), null);

}
collection.remove({'files_id':self.fileId}, function(err, result) {
collection.remove({'files_id':self.fileId}, {safe:true}, function(err, result) {
callback(null, true);

@@ -525,3 +575,3 @@ });

collection.remove({'_id':self.fileId}, function(err, collection) {
collection.remove({'_id':self.fileId}, {safe:true}, function(err, collection) {
callback(err, self);

@@ -657,2 +707,3 @@ });

numberToRead = numberToRead - self.currentChunk.length();
// Load the next chunk and read some more

@@ -839,3 +890,3 @@ self.nthChunk(self.currentChunk.chunkNumber + 1, function(err, chunk) {

*/
GridStore.DEFAULT_CONTENT_TYPE = 'text/plain';
GridStore.DEFAULT_CONTENT_TYPE = 'binary/octet-stream';
/**

@@ -1033,3 +1084,3 @@ * Seek mode where the given length is absolute.

gridStore.collection(function(err, collection) {
collection.remove({'_id':gridStore.fileId}, function(err, collection) {
collection.remove({'_id':gridStore.fileId}, {safe:true}, function(err, collection) {
callback(err, self);

@@ -1083,3 +1134,3 @@ });

var data = gstore.currentChunk.read(toRead);
var data = gstore.currentChunk.readSlice(toRead);
if (data != null) {

@@ -1086,0 +1137,0 @@ self.completedLength += data.length;

@@ -1,27 +0,102 @@

var sys = require('sys')
// // Add both the BSON Pure classes and the native ones
var BSONPure = exports.BSONPure = require('./bson/bson');
var BSONNative = null
try {
BSONNative = exports.BSONNative = require('../../external-libs/bson/bson');
exports.BSONPure = require('./bson/bson');
exports.BSONNative = require('../../external-libs/bson/bson');
} catch(err) {
// do nothing
}
[
'bson/binary_parser',
'commands/base_command', 'commands/db_command', 'commands/delete_command',
'commands/get_more_command', 'commands/insert_command', 'commands/kill_cursor_command',
'commands/query_command', 'commands/update_command',
'responses/mongo_reply',
'admin', 'collection', 'connection', 'cursor', 'db',
'goog/math/integer', 'goog/math/long', 'crypto/md5',
'gridfs/chunk', 'gridfs/gridstore'
].forEach(function(path){
[ 'bson/binary_parser'
, 'commands/base_command'
, 'commands/db_command'
, 'commands/delete_command'
, 'commands/get_more_command'
, 'commands/insert_command'
, 'commands/kill_cursor_command'
, 'commands/query_command'
, 'commands/update_command'
, 'responses/mongo_reply'
, 'admin'
, 'collection'
, 'connections/server'
, 'connections/repl_set_servers'
, 'connection'
, 'cursor'
, 'db'
, 'goog/math/long'
, 'crypto/md5'
, 'gridfs/chunk'
, 'gridfs/gridstore'].forEach(function (path) {
var module = require('./' + path);
for (var i in module)
for (var i in module) {
exports[i] = module[i];
}
});
// Exports all the classes for the NATIVE JS BSON Parser
exports.native = function() {
var classes = {};
// Map all the classes
[ 'bson/binary_parser'
, '../../external-libs/bson/bson'
, 'commands/base_command'
, 'commands/db_command'
, 'commands/delete_command'
, 'commands/get_more_command'
, 'commands/insert_command'
, 'commands/kill_cursor_command'
, 'commands/query_command'
, 'commands/update_command'
, 'responses/mongo_reply'
, 'admin'
, 'collection'
, 'connections/server'
, 'connections/repl_set_servers'
, 'connection'
, 'cursor'
, 'db'
, 'crypto/md5'
, 'gridfs/chunk'
, 'gridfs/gridstore'].forEach(function (path) {
var module = require('./' + path);
for (var i in module) {
classes[i] = module[i];
}
});
// Return classes list
return classes;
}
// Exports all the classes for the PURE JS BSON Parser
exports.pure = function() {
var classes = {};
// Map all the classes
[ 'bson/binary_parser'
, './bson/bson'
, 'commands/base_command'
, 'commands/db_command'
, 'commands/delete_command'
, 'commands/get_more_command'
, 'commands/insert_command'
, 'commands/kill_cursor_command'
, 'commands/query_command'
, 'commands/update_command'
, 'responses/mongo_reply'
, 'admin'
, 'collection'
, 'connections/server'
, 'connections/repl_set_servers'
, 'connection'
, 'cursor'
, 'db'
, 'crypto/md5'
, 'gridfs/chunk'
, 'gridfs/gridstore'].forEach(function (path) {
var module = require('./' + path);
for (var i in module) {
classes[i] = module[i];
}
});
// Return classes list
return classes;
}
var BinaryParser = require('../bson/binary_parser').BinaryParser,
Integer = require('../goog/math/integer').Integer,
Long = require('../goog/math/long').Long;

@@ -4,0 +3,0 @@

{ "name" : "mongodb"
, "description" : "A node.js driver for MongoDB"
, "version" : "0.9.3"
, "version" : "0.9.6-1"
, "author" : "Christian Amor Kvalheim <christkv@gmail.com>"

@@ -5,0 +5,0 @@ , "contributors" : [ "Nathan White <nw@nwhite.net>",

@@ -83,8 +83,12 @@ Install

GridStore
========
=========
The GridStore class allows for storage of binary files in mongoDB using the mongoDB defined files and chunks collection definition.
See the gridfs.js file under examples/ for how to use it or view the integration tests marked with test_gs_...
For more information have a look at [Gridstore](https://github.com/christkv/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/christkv/node-mongodb-native/blob/master/docs/replicaset.md)
Notes

@@ -158,4 +162,4 @@ ========

If this document doesn't answer your questions, see the source of
[Collection](https://github.com/mongodb/mongo-python-driver/blob/master/pymongo/connection.py)
or [Cursor](https://github.com/mongodb/mongo-python-driver/blob/master/pymongo/cursor.py),
[Collection](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js)
or [Cursor](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/cursor.js),
or the documentation at MongoDB for query and update formats.

@@ -162,0 +166,0 @@

@@ -8,2 +8,3 @@

, mongoose = start.mongoose
, should = require('should')
, Schema = mongoose.Schema;

@@ -25,22 +26,41 @@

'test that trying to implement a sparse index throws an error': function () {
var db = start()
, NativeTestCollection = db.model('NativeDriverTest');
'test that trying to implement a sparse index works': function () {
var db = start()
, NativeTestCollection = db.model('NativeDriverTest');
NativeTestCollection.collection.ensureIndex({ title: 1 }, { sparse: true }, function (err) {
err.should.be.an.instanceof(Error);
/driver only implements/.test(err.message).should.be.true;
NativeTestCollection.collection.ensureIndex({ title: 1 }, { sparse: true }, function (err) {
should.strictEqual(!!err, false);
NativeTestCollection.collection.getIndexes(function (err, indexes) {
db.close();
should.strictEqual(!!err, false);
indexes.should.be.instanceof(Object);
indexes['title_1'].should.eql([['title', 1]]);
});
});
},
'test that the -native traditional ensureIndex spec syntax for fields works': function () {
var db = start()
, NativeTestCollection = db.model('NativeDriverTest');
var db = start()
, NativeTestCollection = db.model('NativeDriverTest');
NativeTestCollection.collection.ensureIndex([['a', 1]], function () {
NativeTestCollection.collection.ensureIndex([['a', 1]], function () {
db.close();
});
},
'unique index fails passes error': function () {
var db = start()
, schema = new Schema({ title: String })
, NativeTestCollection = db.model('NativeDriverTestUnique', schema)
NativeTestCollection.create({ title: 'x' }, {title:'x'}, function (err) {
should.strictEqual(!!err, false);
NativeTestCollection.collection.ensureIndex({ title: 1 }, { unique: true }, function (err) {
;/E11000 duplicate key error index/.test(err.message).should.equal(true);
db.close();
});
});
}
};

@@ -144,3 +144,3 @@ //Query.prototype.where(criteria, callback)

UserNS.male.remove( function (err) {
should.strictEqual(err, null);
should.strictEqual(!!err, false);
UserNS.male.find( function (err, found) {

@@ -147,0 +147,0 @@ db.close();

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc