Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Prepped for release to the masses

  • Loading branch information...
commit 5eeca8082c02366508c3252cd43cbd2dd10b3876 2 parents fccdabb + 420c891
SubSonic Project subsonic authored
Showing with 4,144 additions and 3,964 deletions.
  1. BIN  .DS_Store
  2. +16 −1 .gitignore
  3. +12 −0 LICENSE
  4. +28 −0 README.md
  5. +87 −87 iisnode/index.html
  6. +168 −165 lib/congo.js
  7. +5 −5 node_modules/.bin/express.cmd
  8. +5 −5 node_modules/.bin/jade.cmd
  9. +5 −5 node_modules/jade/node_modules/.bin/cake.cmd
  10. +5 −5 node_modules/jade/node_modules/.bin/coffee.cmd
  11. +1,016 −1,016 node_modules/mongoskin/node_modules/mongodb/node_modules/bson/ext/bson.cc
  12. +273 −273 node_modules/mongoskin/node_modules/mongodb/node_modules/bson/ext/bson.h
  13. +28 −26 package.json
  14. +38 −38 public/javascripts/backbone.js
  15. +1,430 −1,430 public/javascripts/backbone_dev.js
  16. +5 −5 public/javascripts/bootstrap.min.js
  17. +95 −95 public/javascripts/congo/base.js
  18. +65 −65 public/javascripts/congo/collections.js
  19. +61 −64 public/javascripts/congo/database.js
  20. +143 −89 public/javascripts/congo/documents.js
  21. +91 −62 public/javascripts/congo/index.js
  22. +90 −52 public/javascripts/congo/nav.js
  23. +124 −124 public/javascripts/jquery-ui.js
  24. +2 −2 public/javascripts/jquery.js
  25. +32 −32 public/javascripts/underscore.js
  26. +9 −9 public/stylesheets/bootstrap-responsive.css
  27. +9 −9 public/stylesheets/bootstrap.css
  28. +44 −42 public/stylesheets/overrides.css
  29. +5 −5 robots.txt
  30. +6 −6 routes/index.js
  31. +35 −35 server.js
  32. +94 −94 views/index.jade
  33. +45 −45 views/layout.jade
  34. +73 −73 web.config
BIN  .DS_Store
View
Binary file not shown
17 .gitignore
View
@@ -1 +1,16 @@
-iisnode
+iisnode
+lib-cov
+*.seed
+*.log
+*.csv
+*.dat
+*.out
+*.pid
+*.gz
+
+pids
+logs
+results
+
+npm-debug.log
+
12 LICENSE
View
@@ -0,0 +1,12 @@
+New BSD License
+http://www.opensource.org/licenses/bsd-license.php
+Copyright (c) 2013, Rob Conery (rob@tekpub.com)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+Neither the name of the Tekpub nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 README.md
View
@@ -0,0 +1,28 @@
+Congo, a Backbone MongoDB Explorer from Tekpub
+=====
+
+A MongoDB Explorer written in Backbone using Twitter Bootstrap. Part of [Tekpub's Backbone.series](http://tekpub.com/productions/backbone)
+
+Congo is a bit of work-in-progress. We need this tool at Tekpub and in course of creating it, decided to record our work and present it to you, along with the project.
+
+There are a number of things that we'd like to add, but right now Congo will:
+
+ - Browse local MongoDB databases, collections, and documents
+ - Allow you to edit each document using the excellent Ace Text Editor
+
+The next work item is building in a query tool, and also some ad-hoc Map Reduce.
+
+### Requirements
+Congo is written in Backbone and, of course, requires MongoDB. The project itself was created in WebMatrix so if you're a Microsoft developer you'll be able to download this directly and open it in WebMatrix 2.
+
+The web server is NodeJS, [so you'll want to have Node installed as well](http://nodejs.org). If you receive errors on first start, run `npm install` in the root of the site (from the command line) to install any modules that don't get loaded from the repo.
+
+### Installation
+Clone this repo: `got clone https://github.com/tekpub/congo.git` into any directory and make sure that MongoDB and Node are installed on your machine. If you're using WebMatrix you can hit "Run" and up it will go.
+
+On Mac/Linux, change directories into Congo and "npm start" to start up the web server. If you receive any errors on start, be sure to make sure that all modules are installed using `npm install -d`
+
+**A note on builds**: Normally there would be some kind of build process which would concat/minify the JS files but we don't find much of a need for that here. Ideally this application won't be served for public consumption and is for admin needs only.
+
+If you do need to build/minify - we suggest using CodeKit, LiveReload, Cassette, or whatever tool you normall use - and make it part of your development process.
+
174 iisnode/index.html
View
@@ -1,87 +1,87 @@
-<html>
-<head>
- <title>iisnode logs</title>
- <style type="text/css">
- body
- {
- font-family: "Trebuchet MS" , Arial, Helvetica, sans-serif;
- }
- table
- {
- border-collapse: collapse;
- }
- td, th
- {
- border: 1px solid lightgray;
- padding: 3px 7px 2px 7px;
- }
- th
- {
- text-align: left;
- padding-top: 5px;
- padding-bottom: 4px;
- background-color: Gray;
- color: #ffffff;
- }
- td.stderr
- {
- color: Red;
- }
- </style>
-</head>
-<body>
- <table id="logFilesTable">
- <tr>
- <th>
- Computer name
- </th>
- <th>
- PID
- </th>
- <th>
- Type
- </th>
- <th>
- Created
- </th>
- <th>
- Link
- </th>
- </tr>
- </table>
- <p id="lastUpdated"></p>
- <script type="text/javascript">
-
- // this is replaced with actual data at runtime by code in interceptor.js
- var logFiles = [{"file":"PUKA-1328-stdout-1358553538996.txt","computername":"PUKA","pid":1328,"type":"stdout","created":1358553538996},{"file":"PUKA-1476-stdout-1358543697505.txt","computername":"PUKA","pid":1476,"type":"stdout","created":1358543697505},{"file":"PUKA-1724-stdout-1358554237344.txt","computername":"PUKA","pid":1724,"type":"stdout","created":1358554237344},{"file":"PUKA-2400-stdout-1358553605351.txt","computername":"PUKA","pid":2400,"type":"stdout","created":1358553605351},{"file":"PUKA-2508-stdout-1358553510667.txt","computername":"PUKA","pid":2508,"type":"stdout","created":1358553510667},{"file":"PUKA-2580-stdout-1358553182486.txt","computername":"PUKA","pid":2580,"type":"stdout","created":1358553182486},{"file":"PUKA-2676-stdout-1358553091880.txt","computername":"PUKA","pid":2676,"type":"stdout","created":1358553091880},{"file":"PUKA-2696-stderr-1358543671614.txt","computername":"PUKA","pid":2696,"type":"stderr","created":1358543671614},{"file":"PUKA-2696-stdout-1358543671600.txt","computername":"PUKA","pid":2696,"type":"stdout","created":1358543671600},{"file":"PUKA-2844-stdout-1358553018821.txt","computername":"PUKA","pid":2844,"type":"stdout","created":1358553018821},{"file":"PUKA-3628-stdout-1358553683342.txt","computername":"PUKA","pid":3628,"type":"stdout","created":1358553683342},{"file":"PUKA-3864-stdout-1358543487698.txt","computername":"PUKA","pid":3864,"type":"stdout","created":1358543487698},{"file":"PUKA-4188-stdout-1358553394351.txt","computername":"PUKA","pid":4188,"type":"stdout","created":1358553394351},{"file":"PUKA-4224-stdout-1358553328732.txt","computername":"PUKA","pid":4224,"type":"stdout","created":1358553328732},{"file":"PUKA-4376-stdout-1358552841203.txt","computername":"PUKA","pid":4376,"type":"stdout","created":1358552841203},{"file":"PUKA-4636-stdout-1358554106795.txt","computername":"PUKA","pid":4636,"type":"stdout","created":1358554106795},{"file":"PUKA-4772-stdout-1358553667325.txt","computername":"PUKA","pid":4772,"type":"stdout","created":1358553667325},{"file":"PUKA-4792-stdout-1358553231439.txt","computername":"PUKA","pid":4792,"type":"stdout","created":1358553231439},{"file":"PUKA-4996-stderr-1358543655299.txt","computername":"PUKA","pid":4996,"type":"stderr","created":1358543655299},{"file":"PUKA-4996-stdout-1358543655276.txt","computername":"PUKA","pid":4996,"type":"stdout","created":1358543655276},{"file":"PUKA-5072-stdout-1358553658552.txt","computername":"PUKA","pid":5072,"type":"stdout","created":1358553658552}];
- var lastUpdated = 1358554237582;
- var date = new Date();
-
- date.setTime(lastUpdated);
- document.getElementById('lastUpdated').innerHTML = 'Index was last updated ' + date;
-
- logFiles.sort(function (a, b) {
- return b.created - a.created;
- });
-
- var logFilesTable = document.getElementById("logFilesTable");
- for (var i = 0; i < logFiles.length; i++) {
- var logFile = logFiles[i];
- date.setTime(logFile.created);
- var row = logFilesTable.insertRow(-1);
- var computerNameCell = row.insertCell(0);
- var pidCell = row.insertCell(1);
- var typeCell = row.insertCell(2);
- var dateCell = row.insertCell(3);
- var logCell = row.insertCell(4);
- computerNameCell.innerHTML = logFile.computername;
- pidCell.innerHTML = logFile.pid.toString();
- typeCell.innerHTML = logFile.type;
- typeCell.setAttribute('class', logFile.type);
- dateCell.innerHTML = date.toString();
- logCell.innerHTML = '<a href="' + logFile.file + '">log</a>';
- };
-
- </script>
-</body>
-</html>
+<html>
+<head>
+ <title>iisnode logs</title>
+ <style type="text/css">
+ body
+ {
+ font-family: "Trebuchet MS" , Arial, Helvetica, sans-serif;
+ }
+ table
+ {
+ border-collapse: collapse;
+ }
+ td, th
+ {
+ border: 1px solid lightgray;
+ padding: 3px 7px 2px 7px;
+ }
+ th
+ {
+ text-align: left;
+ padding-top: 5px;
+ padding-bottom: 4px;
+ background-color: Gray;
+ color: #ffffff;
+ }
+ td.stderr
+ {
+ color: Red;
+ }
+ </style>
+</head>
+<body>
+ <table id="logFilesTable">
+ <tr>
+ <th>
+ Computer name
+ </th>
+ <th>
+ PID
+ </th>
+ <th>
+ Type
+ </th>
+ <th>
+ Created
+ </th>
+ <th>
+ Link
+ </th>
+ </tr>
+ </table>
+ <p id="lastUpdated"></p>
+ <script type="text/javascript">
+
+ // this is replaced with actual data at runtime by code in interceptor.js
+ var logFiles = [{"file":"BLARP-6052-stdout-1359494907870.txt","computername":"BLARP","pid":6052,"type":"stdout","created":1359494907870},{"file":"BLARP-6680-stdout-1359494654898.txt","computername":"BLARP","pid":6680,"type":"stdout","created":1359494654898},{"file":"BLARP-7080-stdout-1359424511540.txt","computername":"BLARP","pid":7080,"type":"stdout","created":1359424511540},{"file":"BLARP-720-stdout-1359495426737.txt","computername":"BLARP","pid":720,"type":"stdout","created":1359495426737},{"file":"BLARP-7660-stdout-1359495909174.txt","computername":"BLARP","pid":7660,"type":"stdout","created":1359495909174},{"file":"BLARP-976-stdout-1359495348674.txt","computername":"BLARP","pid":976,"type":"stdout","created":1359495348674},{"file":"PUKA-1348-stdout-1359152705550.txt","computername":"PUKA","pid":1348,"type":"stdout","created":1359152705550},{"file":"PUKA-2308-stderr-1359576346092.txt","computername":"PUKA","pid":2308,"type":"stderr","created":1359576346092},{"file":"PUKA-2308-stdout-1359576345764.txt","computername":"PUKA","pid":2308,"type":"stdout","created":1359576345764},{"file":"PUKA-2504-stdout-1359151140083.txt","computername":"PUKA","pid":2504,"type":"stdout","created":1359151140083},{"file":"PUKA-3188-stdout-1359577008945.txt","computername":"PUKA","pid":3188,"type":"stdout","created":1359577008945},{"file":"PUKA-3764-stdout-1359143401944.txt","computername":"PUKA","pid":3764,"type":"stdout","created":1359143401944},{"file":"PUKA-3788-stdout-1359143317170.txt","computername":"PUKA","pid":3788,"type":"stdout","created":1359143317170},{"file":"PUKA-4044-stdout-1359583170970.txt","computername":"PUKA","pid":4044,"type":"stdout","created":1359583170970},{"file":"PUKA-4532-stdout-1359422182278.txt","computername":"PUKA","pid":4532,"type":"stdout","created":1359422182278},{"file":"PUKA-4808-stdout-1359582299791.txt","computername":"PUKA","pid":4808,"type":"stdout","created":1359582299791},{"file":"PUKA-5452-stdout-1359400950079.txt","computername":"PUKA","pid":5452,"type":"stdout","created":1359400950079},{"file":"PUKA-5504-stdout-1359401218459.txt","computername":"PUKA","pid":5504,"type":"stdout","created":1359401218459},{"file":"PUKA-5608-stdout-1359422501190.txt","computername":"PUKA","pid":5608,"type":"stdout","created":1359422501190},{"file":"PUKA-5784-stdout-1359400394264.txt","computername":"PUKA","pid":5784,"type":"stdout","created":1359400394264}];
+ var lastUpdated = 1359583171208;
+ var date = new Date();
+
+ date.setTime(lastUpdated);
+ document.getElementById('lastUpdated').innerHTML = 'Index was last updated ' + date;
+
+ logFiles.sort(function (a, b) {
+ return b.created - a.created;
+ });
+
+ var logFilesTable = document.getElementById("logFilesTable");
+ for (var i = 0; i < logFiles.length; i++) {
+ var logFile = logFiles[i];
+ date.setTime(logFile.created);
+ var row = logFilesTable.insertRow(-1);
+ var computerNameCell = row.insertCell(0);
+ var pidCell = row.insertCell(1);
+ var typeCell = row.insertCell(2);
+ var dateCell = row.insertCell(3);
+ var logCell = row.insertCell(4);
+ computerNameCell.innerHTML = logFile.computername;
+ pidCell.innerHTML = logFile.pid.toString();
+ typeCell.innerHTML = logFile.type;
+ typeCell.setAttribute('class', logFile.type);
+ dateCell.innerHTML = date.toString();
+ logCell.innerHTML = '<a href="' + logFile.file + '">log</a>';
+ };
+
+ </script>
+</body>
+</html>
333 lib/congo.js
View
@@ -1,165 +1,168 @@
-var mongo = require("mongoskin");
-var _app = {};
-var _ = require("underscore")._;
-
-var Congo = function(app){
- var congo = {};
-
- var connect = function(dbName,next){
- var db = mongo.db("localhost/" + dbName, {safe : true});
- next(db);
- }
-
- app.post("/mongo-api/query", function(req,res){
- var dbName = req.body.db;
- var collection = req.body.collection;
- var queryText = req.body.query;
- if(queryText.substring(0,1) != "{"){
- queryText = "{" + queryText + "}";
- }
- var query = JSON.parse(queryText);
- connect(dbName, function(db){
- db.collection(collection).find(query).toArray(function(err,response){
- console.log(response);
- res.json(response);
- });
- })
-
- });
-
- app.get("/mongo-api/dbs",function(req,res){
- var out = [];
- connect("admin",function(db){
- db.admin.listDatabases(function(err,result){
- _.each(result.databases,function(item){
- var formatted = {
- name : item.name,
- _url : "http://" + req.headers.host + "/mongo/" + item.name
- };
- out.push(formatted);
- });
- res.json(out);
- });
- });
- });
- app.delete("/mongo-api/dbs/:db",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- db.dropDatabase(function(err,result){
- res.json(result);
- });
- });
- });
- app.put("/mongo-api/dbs/:db",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- db.createCollection("users",function(err,result){
- res.json({name : dbName});
- });
- });
-
- });
-
- app.get("/mongo-api/:db",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- var out = [];
- db.collectionNames(function(err,collNames){
- _.each(collNames, function(collName){
- var cleanName = collName.name.replace(dbName + ".","");
- var formatted = {
- name : cleanName,
- _url : "http://" + req.headers.host + "/mongo/" + dbName + "/" + cleanName,
- database : dbName
- };
- if(cleanName != "system.indexes")
- out.push(formatted);
- });
- res.json(out);
- });
- });
- });
-
- app.put("/mongo-api/:db/:collection",function(req,res){
- //adds a collection
- var collectionName = req.params.collection;
- var dbName = req.params.db;
- var out = [];
- connect(dbName, function(db){
- db.createCollection(collectionName, function(err,result){
- res.json({name : collectionName});
- });
- });
- });
-
- app.get("/mongo-api/:db/:collection",function(req,res){
- var dbName = req.params.db;
- var collName = req.params.collection;
- var out = [];
- connect(dbName, function(db){
- db.collection(collName).find().limit(50).toArray(function(err,items){
- _.each(items,function(item){
- var formatted = item;
- });
-
- res.json(items);
- });
- });
- });
- app.get("/mongo-api/:db/:collection/:id",function(req,res){
- var dbName = req.params.db;
- var id = req.params.id;
- var collName = req.params.collection;
- connect(dbName, function(db){
- db.collection(collName).findById(id,function(err,doc){
- res.json(doc);
- });
- });
- });
- app.delete("/mongo-api/:db/:collection", function(req,res) {
- var dbName = req.params.db;
- connect(dbName, function(db){
- db.dropCollection(req.params.collection,function(err,result){
- res.json(result);
- });
- });
- });
-
- app.delete("/mongo-api/:db/:collection/:id",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- db.collection(req.params.collection).removeById(req.params.id,function(err,result){
- res.json(result);
- });
- });
- });
-
- app.post("/mongo-api/:db/:collection",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- var doc = req.body;
- db.collection(req.params.collection).insert(doc, function(err,result){
- var out ={error : err, result : result};
- res.json(out);
- });
- });
- });
-
- app.put("/mongo-api/:db/:collection/:id",function(req,res){
- var dbName = req.params.db;
- connect(dbName, function(db){
- var doc = req.body;
- delete doc._id;
- db.collection(req.params.collection).updateById(req.params.id, doc, {}, function(err,result){
- var out ={error : err, result : result};
- res.json(out);
- });
- });
- });
-
- congo.app = app;
- return congo;
-
-};
-
-module.exports = Congo;
+var mongo = require("mongoskin");
+var _app = {};
+var _ = require("underscore")._;
+
+var Congo = function(app){
+ var congo = {};
+
+ //assume localhost
+ var connect = function(dbName,next){
+ var db = mongo.db("localhost/" + dbName, {safe : true});
+ next(db);
+ }
+ //stubbed query method for later use
+ app.post("/mongo-api/query", function(req,res){
+ var dbName = req.body.db;
+ var collection = req.body.collection;
+ var queryText = req.body.query;
+ if(queryText.substring(0,1) != "{"){
+ queryText = "{" + queryText + "}";
+ }
+ var query = JSON.parse(queryText);
+ connect(dbName, function(db){
+ db.collection(collection).find(query).toArray(function(err,response){
+ console.log(response);
+ res.json(response);
+ });
+ })
+
+ });
+
+ //list of all databases
+ app.get("/mongo-api/dbs",function(req,res){
+ var out = [];
+ connect("admin",function(db){
+ db.admin.listDatabases(function(err,result){
+ _.each(result.databases,function(item){
+ var formatted = {
+ name : item.name,
+ _url : "http://" + req.headers.host + "/mongo/" + item.name
+ };
+ out.push(formatted);
+ });
+ res.json(out);
+ });
+ });
+ });
+
+ app.delete("/mongo-api/dbs/:db",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ db.dropDatabase(function(err,result){
+ res.json(result);
+ });
+ });
+ });
+ app.put("/mongo-api/dbs/:db",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ db.createCollection("users",function(err,result){
+ res.json({name : dbName});
+ });
+ });
+
+ });
+
+ app.get("/mongo-api/:db",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ var out = [];
+ db.collectionNames(function(err,collNames){
+ _.each(collNames, function(collName){
+ var cleanName = collName.name.replace(dbName + ".","");
+ var formatted = {
+ name : cleanName,
+ _url : "http://" + req.headers.host + "/mongo/" + dbName + "/" + cleanName,
+ database : dbName
+ };
+ if(cleanName != "system.indexes")
+ out.push(formatted);
+ });
+ res.json(out);
+ });
+ });
+ });
+
+ app.put("/mongo-api/:db/:collection",function(req,res){
+ //adds a collection
+ var collectionName = req.params.collection;
+ var dbName = req.params.db;
+ var out = [];
+ connect(dbName, function(db){
+ db.createCollection(collectionName, function(err,result){
+ res.json({name : collectionName});
+ });
+ });
+ });
+
+ app.get("/mongo-api/:db/:collection",function(req,res){
+ var dbName = req.params.db;
+ var collName = req.params.collection;
+ var out = [];
+ connect(dbName, function(db){
+ db.collection(collName).find().limit(50).toArray(function(err,items){
+ _.each(items,function(item){
+ var formatted = item;
+ });
+
+ res.json(items);
+ });
+ });
+ });
+ app.get("/mongo-api/:db/:collection/:id",function(req,res){
+ var dbName = req.params.db;
+ var id = req.params.id;
+ var collName = req.params.collection;
+ connect(dbName, function(db){
+ db.collection(collName).findById(id,function(err,doc){
+ res.json(doc);
+ });
+ });
+ });
+ app.delete("/mongo-api/:db/:collection", function(req,res) {
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ db.dropCollection(req.params.collection,function(err,result){
+ res.json(result);
+ });
+ });
+ });
+
+ app.delete("/mongo-api/:db/:collection/:id",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ db.collection(req.params.collection).removeById(req.params.id,function(err,result){
+ res.json(result);
+ });
+ });
+ });
+
+ app.post("/mongo-api/:db/:collection",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ var doc = req.body;
+ db.collection(req.params.collection).insert(doc, function(err,result){
+ var out ={error : err, result : result};
+ res.json(out);
+ });
+ });
+ });
+
+ app.put("/mongo-api/:db/:collection/:id",function(req,res){
+ var dbName = req.params.db;
+ connect(dbName, function(db){
+ var doc = req.body;
+ delete doc._id;
+ db.collection(req.params.collection).updateById(req.params.id, doc, {}, function(err,result){
+ var out ={error : err, result : result};
+ res.json(out);
+ });
+ });
+ });
+
+ congo.app = app;
+ return congo;
+
+};
+
+module.exports = Congo;
10 node_modules/.bin/express.cmd
View
@@ -1,6 +1,6 @@
-:: Created by npm, please don't edit manually.
-@IF EXIST "%~dp0\node.exe" (
- "%~dp0\node.exe" "%~dp0\..\express\bin\express" %*
-) ELSE (
- node "%~dp0\..\express\bin\express" %*
+:: Created by npm, please don't edit manually.
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\express\bin\express" %*
+) ELSE (
+ node "%~dp0\..\express\bin\express" %*
)
10 node_modules/.bin/jade.cmd
View
@@ -1,6 +1,6 @@
-:: Created by npm, please don't edit manually.
-@IF EXIST "%~dp0\node.exe" (
- "%~dp0\node.exe" "%~dp0\..\jade\bin\jade" %*
-) ELSE (
- node "%~dp0\..\jade\bin\jade" %*
+:: Created by npm, please don't edit manually.
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\jade\bin\jade" %*
+) ELSE (
+ node "%~dp0\..\jade\bin\jade" %*
)
10 node_modules/jade/node_modules/.bin/cake.cmd
View
@@ -1,6 +1,6 @@
-:: Created by npm, please don't edit manually.
-@IF EXIST "%~dp0\node.exe" (
- "%~dp0\node.exe" "%~dp0\..\coffee-script\bin\cake" %*
-) ELSE (
- node "%~dp0\..\coffee-script\bin\cake" %*
+:: Created by npm, please don't edit manually.
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\coffee-script\bin\cake" %*
+) ELSE (
+ node "%~dp0\..\coffee-script\bin\cake" %*
)
10 node_modules/jade/node_modules/.bin/coffee.cmd
View
@@ -1,6 +1,6 @@
-:: Created by npm, please don't edit manually.
-@IF EXIST "%~dp0\node.exe" (
- "%~dp0\node.exe" "%~dp0\..\coffee-script\bin\coffee" %*
-) ELSE (
- node "%~dp0\..\coffee-script\bin\coffee" %*
+:: Created by npm, please don't edit manually.
+@IF EXIST "%~dp0\node.exe" (
+ "%~dp0\node.exe" "%~dp0\..\coffee-script\bin\coffee" %*
+) ELSE (
+ node "%~dp0\..\coffee-script\bin\coffee" %*
)
2,032 node_modules/mongoskin/node_modules/mongodb/node_modules/bson/ext/bson.cc
View
@@ -1,1016 +1,1016 @@
-//===========================================================================
-
-#include <stdarg.h>
-#include <cstdlib>
-#include <cstring>
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-parameter"
-#endif
-
-#include <v8.h>
-
-// this and the above block must be around the v8.h header otherwise
-// v8 is not happy
-#ifdef __clang__
-#pragma clang diagnostic pop
-#endif
-
-#include <node.h>
-#include <node_version.h>
-#include <node_buffer.h>
-
-#include <cmath>
-#include <iostream>
-#include <limits>
-#include <vector>
-
-#include "bson.h"
-
-using namespace v8;
-using namespace node;
-
-//===========================================================================
-
-void DataStream::WriteObjectId(const Handle<Object>& object, const Handle<String>& key)
-{
- uint16_t buffer[12];
- object->Get(key)->ToString()->Write(buffer, 0, 12);
- for(uint32_t i = 0; i < 12; ++i)
- {
- *p++ = (char) buffer[i];
- }
-}
-
-void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...)
-{
- va_list args;
- va_start(args, format);
- char* string = (char*) malloc(allocationSize);
- vsprintf(string, format, args);
- va_end(args);
-
- throw string;
-}
-
-void DataStream::CheckKey(const Local<String>& keyName)
-{
- size_t keyLength = keyName->Utf8Length();
- if(keyLength == 0) return;
-
- char* keyStringBuffer = (char*) alloca(keyLength+1);
- keyName->WriteUtf8(keyStringBuffer);
-
- if(keyStringBuffer[0] == '$')
- {
- ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer);
- }
-
- if(strchr(keyStringBuffer, '.') != NULL)
- {
- ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer);
- }
-}
-
-template<typename T> void BSONSerializer<T>::SerializeDocument(const Handle<Value>& value)
-{
- void* documentSize = this->BeginWriteSize();
- Local<Object> object = bson->GetSerializeObject(value);
-
- // Get the object property names
- #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
- Local<Array> propertyNames = object->GetPropertyNames();
- #else
- Local<Array> propertyNames = object->GetOwnPropertyNames();
- #endif
-
- // Length of the property
- int propertyLength = propertyNames->Length();
- for(int i = 0; i < propertyLength; ++i)
- {
- const Local<String>& propertyName = propertyNames->Get(i)->ToString();
- if(checkKeys) this->CheckKey(propertyName);
-
- const Local<Value>& propertyValue = object->Get(propertyName);
-
- if(serializeFunctions || !propertyValue->IsFunction())
- {
- void* typeLocation = this->BeginWriteType();
- this->WriteString(propertyName);
- SerializeValue(typeLocation, propertyValue);
- }
- }
-
- this->WriteByte(0);
- this->CommitSize(documentSize);
-}
-
-template<typename T> void BSONSerializer<T>::SerializeArray(const Handle<Value>& value)
-{
- void* documentSize = this->BeginWriteSize();
-
- Local<Array> array = Local<Array>::Cast(value->ToObject());
- uint32_t arrayLength = array->Length();
-
- for(uint32_t i = 0; i < arrayLength; ++i)
- {
- void* typeLocation = this->BeginWriteType();
- this->WriteUInt32String(i);
- SerializeValue(typeLocation, array->Get(i));
- }
-
- this->WriteByte(0);
- this->CommitSize(documentSize);
-}
-
-// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes.
-// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths)
-// and ensures that there is always consistency between bytes counted and bytes written by design.
-template<typename T> void BSONSerializer<T>::SerializeValue(void* typeLocation, const Handle<Value>& value)
-{
- if(value->IsNumber())
- {
- double doubleValue = value->NumberValue();
- int intValue = (int) doubleValue;
- if(intValue == doubleValue)
- {
- this->CommitType(typeLocation, BSON_TYPE_INT);
- this->WriteInt32(intValue);
- }
- else
- {
- this->CommitType(typeLocation, BSON_TYPE_NUMBER);
- this->WriteDouble(doubleValue);
- }
- }
- else if(value->IsString())
- {
- this->CommitType(typeLocation, BSON_TYPE_STRING);
- this->WriteLengthPrefixedString(value->ToString());
- }
- else if(value->IsBoolean())
- {
- this->CommitType(typeLocation, BSON_TYPE_BOOLEAN);
- this->WriteBool(value);
- }
- else if(value->IsArray())
- {
- this->CommitType(typeLocation, BSON_TYPE_ARRAY);
- SerializeArray(value);
- }
- else if(value->IsDate())
- {
- this->CommitType(typeLocation, BSON_TYPE_DATE);
- this->WriteInt64(value);
- }
- else if(value->IsRegExp())
- {
- this->CommitType(typeLocation, BSON_TYPE_REGEXP);
- const Handle<RegExp>& regExp = Handle<RegExp>::Cast(value);
-
- this->WriteString(regExp->GetSource());
-
- int flags = regExp->GetFlags();
- if(flags & RegExp::kGlobal) this->WriteByte('s');
- if(flags & RegExp::kIgnoreCase) this->WriteByte('i');
- if(flags & RegExp::kMultiline) this->WriteByte('m');
- this->WriteByte(0);
- }
- else if(value->IsFunction())
- {
- this->CommitType(typeLocation, BSON_TYPE_CODE);
- this->WriteLengthPrefixedString(value->ToString());
- }
- else if(value->IsObject())
- {
- const Local<Object>& object = value->ToObject();
- if(object->Has(bson->_bsontypeString))
- {
- const Local<String>& constructorString = object->GetConstructorName();
- if(bson->longString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_LONG);
- this->WriteInt32(object, bson->_longLowString);
- this->WriteInt32(object, bson->_longHighString);
- }
- else if(bson->timestampString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP);
- this->WriteInt32(object, bson->_longLowString);
- this->WriteInt32(object, bson->_longHighString);
- }
- else if(bson->objectIDString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_OID);
- this->WriteObjectId(object, bson->_objectIDidString);
- }
- else if(bson->binaryString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_BINARY);
-
- uint32_t length = object->Get(bson->_binaryPositionString)->Uint32Value();
- Local<Object> bufferObj = object->Get(bson->_binaryBufferString)->ToObject();
-
- this->WriteInt32(length);
- this->WriteByte(object, bson->_binarySubTypeString); // write subtype
- this->WriteData(Buffer::Data(bufferObj), length);
- }
- else if(bson->doubleString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_NUMBER);
- this->WriteDouble(object, bson->_doubleValueString);
- }
- else if(bson->symbolString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_SYMBOL);
- this->WriteLengthPrefixedString(object->Get(bson->_symbolValueString)->ToString());
- }
- else if(bson->codeString->StrictEquals(constructorString))
- {
- const Local<String>& function = object->Get(bson->_codeCodeString)->ToString();
- const Local<Object>& scope = object->Get(bson->_codeScopeString)->ToObject();
-
- // For Node < 0.6.X use the GetPropertyNames
- #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
- uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
- #else
- uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
- #endif
-
- if(propertyNameLength > 0)
- {
- this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE);
- void* codeWidthScopeSize = this->BeginWriteSize();
- this->WriteLengthPrefixedString(function->ToString());
- SerializeDocument(scope);
- this->CommitSize(codeWidthScopeSize);
- }
- else
- {
- this->CommitType(typeLocation, BSON_TYPE_CODE);
- this->WriteLengthPrefixedString(function->ToString());
- }
- }
- else if(bson->dbrefString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_OBJECT);
-
- void* dbRefSize = this->BeginWriteSize();
-
- void* refType = this->BeginWriteType();
- this->WriteData("$ref", 5);
- SerializeValue(refType, object->Get(bson->_dbRefNamespaceString));
-
- void* idType = this->BeginWriteType();
- this->WriteData("$id", 4);
- SerializeValue(idType, object->Get(bson->_dbRefOidString));
-
- const Local<Value>& refDbValue = object->Get(bson->_dbRefDbString);
- if(!refDbValue->IsUndefined())
- {
- void* dbType = this->BeginWriteType();
- this->WriteData("$db", 4);
- SerializeValue(dbType, refDbValue);
- }
-
- this->WriteByte(0);
- this->CommitSize(dbRefSize);
- }
- else if(bson->minKeyString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_MIN_KEY);
- }
- else if(bson->maxKeyString->StrictEquals(constructorString))
- {
- this->CommitType(typeLocation, BSON_TYPE_MAX_KEY);
- }
- }
- else if(Buffer::HasInstance(value))
- {
- this->CommitType(typeLocation, BSON_TYPE_BINARY);
-
- #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(value->ToObject());
- uint32_t length = object->length();
- #else
- uint32_t length = Buffer::Length(value->ToObject());
- #endif
-
- this->WriteInt32(length);
- this->WriteByte(0);
- this->WriteData(Buffer::Data(value->ToObject()), length);
- }
- else
- {
- this->CommitType(typeLocation, BSON_TYPE_OBJECT);
- SerializeDocument(value);
- }
- }
- else if(value->IsNull() || value->IsUndefined())
- {
- this->CommitType(typeLocation, BSON_TYPE_NULL);
- }
-}
-
-// Data points to start of element list, length is length of entire document including '\0' but excluding initial size
-BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length)
-: bson(aBson),
- pStart(data),
- p(data),
- pEnd(data + length - 1)
-{
- if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
-}
-
-BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length)
-: bson(parentSerializer.bson),
- pStart(parentSerializer.p),
- p(parentSerializer.p),
- pEnd(parentSerializer.p + length - 1)
-{
- parentSerializer.p += length;
- if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds");
- if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
-}
-
-Local<String> BSONDeserializer::ReadCString()
-{
- char* start = p;
- while(*p++) { }
- return String::New(start, (int32_t) (p-start-1) );
-}
-
-int32_t BSONDeserializer::ReadRegexOptions()
-{
- int32_t options = 0;
- for(;;)
- {
- switch(*p++)
- {
- case '\0': return options;
- case 's': options |= RegExp::kGlobal; break;
- case 'i': options |= RegExp::kIgnoreCase; break;
- case 'm': options |= RegExp::kMultiline; break;
- }
- }
-}
-
-uint32_t BSONDeserializer::ReadIntegerString()
-{
- uint32_t value = 0;
- while(*p)
- {
- if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array");
- value = value * 10 + *p++ - '0';
- }
- ++p;
- return value;
-}
-
-Local<String> BSONDeserializer::ReadString()
-{
- uint32_t length = ReadUInt32();
- char* start = p;
- p += length;
- return String::New(start, length-1);
-}
-
-Local<String> BSONDeserializer::ReadObjectId()
-{
- uint16_t objectId[12];
- for(size_t i = 0; i < 12; ++i)
- {
- objectId[i] = *reinterpret_cast<unsigned char*>(p++);
- }
- return String::New(objectId, 12);
-}
-
-Handle<Value> BSONDeserializer::DeserializeDocument()
-{
- uint32_t length = ReadUInt32();
- if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes");
-
- BSONDeserializer documentDeserializer(*this, length-4);
- return documentDeserializer.DeserializeDocumentInternal();
-}
-
-Handle<Value> BSONDeserializer::DeserializeDocumentInternal()
-{
- Local<Object> returnObject = Object::New();
-
- while(HasMoreData())
- {
- BsonType type = (BsonType) ReadByte();
- const Local<String>& name = ReadCString();
- const Handle<Value>& value = DeserializeValue(type);
- returnObject->ForceSet(name, value);
- }
- if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes");
-
- // From JavaScript:
- // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
- if(returnObject->Has(bson->_dbRefIdRefString))
- {
- Local<Value> argv[] = { returnObject->Get(bson->_dbRefRefString), returnObject->Get(bson->_dbRefIdRefString), returnObject->Get(bson->_dbRefDbRefString) };
- return bson->dbrefConstructor->NewInstance(3, argv);
- }
- else
- {
- return returnObject;
- }
-}
-
-Handle<Value> BSONDeserializer::DeserializeArray()
-{
- uint32_t length = ReadUInt32();
- if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes");
-
- BSONDeserializer documentDeserializer(*this, length-4);
- return documentDeserializer.DeserializeArrayInternal();
-}
-
-Handle<Value> BSONDeserializer::DeserializeArrayInternal()
-{
- Local<Array> returnArray = Array::New();
-
- while(HasMoreData())
- {
- BsonType type = (BsonType) ReadByte();
- uint32_t index = ReadIntegerString();
- const Handle<Value>& value = DeserializeValue(type);
- returnArray->Set(index, value);
- }
- if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes");
-
- return returnArray;
-}
-
-Handle<Value> BSONDeserializer::DeserializeValue(BsonType type)
-{
- switch(type)
- {
- case BSON_TYPE_STRING:
- return ReadString();
-
- case BSON_TYPE_INT:
- return Integer::New(ReadInt32());
-
- case BSON_TYPE_NUMBER:
- return Number::New(ReadDouble());
-
- case BSON_TYPE_NULL:
- return Null();
-
- case BSON_TYPE_UNDEFINED:
- return Undefined();
-
- case BSON_TYPE_TIMESTAMP:
- {
- int32_t lowBits = ReadInt32();
- int32_t highBits = ReadInt32();
- Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
- return bson->timestampConstructor->NewInstance(2, argv);
- }
-
- case BSON_TYPE_BOOLEAN:
- return (ReadByte() != 0) ? True() : False();
-
- case BSON_TYPE_REGEXP:
- {
- const Local<String>& regex = ReadCString();
- int32_t options = ReadRegexOptions();
- return RegExp::New(regex, (RegExp::Flags) options);
- }
-
- case BSON_TYPE_CODE:
- {
- const Local<Value>& code = ReadString();
- const Local<Value>& scope = Object::New();
- Local<Value> argv[] = { code, scope };
- return bson->codeConstructor->NewInstance(2, argv);
- }
-
- case BSON_TYPE_CODE_W_SCOPE:
- {
- ReadUInt32();
- const Local<Value>& code = ReadString();
- const Handle<Value>& scope = DeserializeDocument();
- Local<Value> argv[] = { code, scope->ToObject() };
- return bson->codeConstructor->NewInstance(2, argv);
- }
-
- case BSON_TYPE_OID:
- {
- Local<Value> argv[] = { ReadObjectId() };
- return bson->objectIDConstructor->NewInstance(1, argv);
- }
-
- case BSON_TYPE_BINARY:
- {
- uint32_t length = ReadUInt32();
- uint32_t subType = ReadByte();
- Buffer* buffer = Buffer::New(p, length);
- p += length;
-
- Handle<Value> argv[] = { buffer->handle_, Uint32::New(subType) };
- return bson->binaryConstructor->NewInstance(2, argv);
- }
-
- case BSON_TYPE_LONG:
- {
- // Read 32 bit integers
- int32_t lowBits = (int32_t) ReadInt32();
- int32_t highBits = (int32_t) ReadInt32();
-
- // If value is < 2^53 and >-2^53
- if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
- // Adjust the pointer and read as 64 bit value
- p -= 8;
- // Read the 64 bit value
- int64_t finalValue = (int64_t) ReadInt64();
- return Number::New(finalValue);
- }
-
- Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
- return bson->longConstructor->NewInstance(2, argv);
- }
-
- case BSON_TYPE_DATE:
- return Date::New((double) ReadInt64());
-
- case BSON_TYPE_ARRAY:
- return DeserializeArray();
-
- case BSON_TYPE_OBJECT:
- return DeserializeDocument();
-
- case BSON_TYPE_SYMBOL:
- {
- const Local<String>& string = ReadString();
- Local<Value> argv[] = { string };
- return bson->symbolConstructor->NewInstance(1, argv);
- }
-
- case BSON_TYPE_MIN_KEY:
- return bson->minKeyConstructor->NewInstance();
-
- case BSON_TYPE_MAX_KEY:
- return bson->maxKeyConstructor->NewInstance();
-
- default:
- ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type);
- }
-
- return v8::Null();
-}
-
-
-static Handle<Value> VException(const char *msg)
-{
- HandleScope scope;
- return ThrowException(Exception::Error(String::New(msg)));
-}
-
-Persistent<FunctionTemplate> BSON::constructor_template;
-
-BSON::BSON() : ObjectWrap()
-{
- // Setup pre-allocated comparision objects
- _bsontypeString = Persistent<String>::New(String::New("_bsontype"));
- _longLowString = Persistent<String>::New(String::New("low_"));
- _longHighString = Persistent<String>::New(String::New("high_"));
- _objectIDidString = Persistent<String>::New(String::New("id"));
- _binaryPositionString = Persistent<String>::New(String::New("position"));
- _binarySubTypeString = Persistent<String>::New(String::New("sub_type"));
- _binaryBufferString = Persistent<String>::New(String::New("buffer"));
- _doubleValueString = Persistent<String>::New(String::New("value"));
- _symbolValueString = Persistent<String>::New(String::New("value"));
- _dbRefRefString = Persistent<String>::New(String::New("$ref"));
- _dbRefIdRefString = Persistent<String>::New(String::New("$id"));
- _dbRefDbRefString = Persistent<String>::New(String::New("$db"));
- _dbRefNamespaceString = Persistent<String>::New(String::New("namespace"));
- _dbRefDbString = Persistent<String>::New(String::New("db"));
- _dbRefOidString = Persistent<String>::New(String::New("oid"));
- _codeCodeString = Persistent<String>::New(String::New("code"));
- _codeScopeString = Persistent<String>::New(String::New("scope"));
- _toBSONString = Persistent<String>::New(String::New("toBSON"));
-
- longString = Persistent<String>::New(String::New("Long"));
- objectIDString = Persistent<String>::New(String::New("ObjectID"));
- binaryString = Persistent<String>::New(String::New("Binary"));
- codeString = Persistent<String>::New(String::New("Code"));
- dbrefString = Persistent<String>::New(String::New("DBRef"));
- symbolString = Persistent<String>::New(String::New("Symbol"));
- doubleString = Persistent<String>::New(String::New("Double"));
- timestampString = Persistent<String>::New(String::New("Timestamp"));
- minKeyString = Persistent<String>::New(String::New("MinKey"));
- maxKeyString = Persistent<String>::New(String::New("MaxKey"));
-}
-
-void BSON::Initialize(v8::Handle<v8::Object> target)
-{
- // Grab the scope of the call from Node
- HandleScope scope;
- // Define a new function template
- Local<FunctionTemplate> t = FunctionTemplate::New(New);
- constructor_template = Persistent<FunctionTemplate>::New(t);
- constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
- constructor_template->SetClassName(String::NewSymbol("BSON"));
-
- // Instance methods
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize);
- NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream);
-
- target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction());
-}
-
-// Create a new instance of BSON and passing it the existing context
-Handle<Value> BSON::New(const Arguments &args)
-{
- HandleScope scope;
-
- // Check that we have an array
- if(args.Length() == 1 && args[0]->IsArray())
- {
- // Cast the array to a local reference
- Local<Array> array = Local<Array>::Cast(args[0]);
-
- if(array->Length() > 0)
- {
- // Create a bson object instance and return it
- BSON *bson = new BSON();
-
- uint32_t foundClassesMask = 0;
-
- // Iterate over all entries to save the instantiate funtions
- for(uint32_t i = 0; i < array->Length(); i++)
- {
- // Let's get a reference to the function
- Local<Function> func = Local<Function>::Cast(array->Get(i));
- Local<String> functionName = func->GetName()->ToString();
-
- // Save the functions making them persistant handles (they don't get collected)
- if(functionName->StrictEquals(bson->longString))
- {
- bson->longConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 1;
- }
- else if(functionName->StrictEquals(bson->objectIDString))
- {
- bson->objectIDConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 2;
- }
- else if(functionName->StrictEquals(bson->binaryString))
- {
- bson->binaryConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 4;
- }
- else if(functionName->StrictEquals(bson->codeString))
- {
- bson->codeConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 8;
- }
- else if(functionName->StrictEquals(bson->dbrefString))
- {
- bson->dbrefConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x10;
- }
- else if(functionName->StrictEquals(bson->symbolString))
- {
- bson->symbolConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x20;
- }
- else if(functionName->StrictEquals(bson->doubleString))
- {
- bson->doubleConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x40;
- }
- else if(functionName->StrictEquals(bson->timestampString))
- {
- bson->timestampConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x80;
- }
- else if(functionName->StrictEquals(bson->minKeyString))
- {
- bson->minKeyConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x100;
- }
- else if(functionName->StrictEquals(bson->maxKeyString))
- {
- bson->maxKeyConstructor = Persistent<Function>::New(func);
- foundClassesMask |= 0x200;
- }
- }
-
- // Check if we have the right number of constructors otherwise throw an error
- if(foundClassesMask != 0x3ff)
- {
- delete bson;
- return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
- }
- else
- {
- bson->Wrap(args.This());
- return args.This();
- }
- }
- else
- {
- return VException("No types passed in");
- }
- }
- else
- {
- return VException("Argument passed in must be an array of types");
- }
-}
-
-//------------------------------------------------------------------------------------------------
-//------------------------------------------------------------------------------------------------
-//------------------------------------------------------------------------------------------------
-//------------------------------------------------------------------------------------------------
-
-Handle<Value> BSON::BSONDeserialize(const Arguments &args)
-{
- HandleScope scope;
-
- // Ensure that we have an parameter
- if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1.");
- if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1.");
- // Throw an exception if the argument is not of type Buffer
- if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String.");
-
- // Define pointer to data
- Local<Object> obj = args[0]->ToObject();
-
- // Unpack the BSON parser instance
- BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
-
- // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
- if(Buffer::HasInstance(obj))
- {
-#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
- char* data = buffer->data();
- size_t length = buffer->length();
-#else
- char* data = Buffer::Data(obj);
- size_t length = Buffer::Length(obj);
-#endif
-
- // Validate that we have at least 5 bytes
- if(length < 5) return VException("corrupt bson message < 5 bytes long");
-
- try
- {
- BSONDeserializer deserializer(bson, data, length);
- return deserializer.DeserializeDocument();
- }
- catch(char* exception)
- {
- Handle<Value> error = VException(exception);
- free(exception);
- return error;
- }
-
- }
- else
- {
- // The length of the data for this encoding
- ssize_t len = DecodeBytes(args[0], BINARY);
-
- // Validate that we have at least 5 bytes
- if(len < 5) return VException("corrupt bson message < 5 bytes long");
-
- // Let's define the buffer size
- char* data = (char *)malloc(len);
- DecodeWrite(data, len, args[0], BINARY);
-
- try
- {
- BSONDeserializer deserializer(bson, data, len);
- Handle<Value> result = deserializer.DeserializeDocument();
- free(data);
- return result;
-
- }
- catch(char* exception)
- {
- Handle<Value> error = VException(exception);
- free(exception);
- free(data);
- return error;
- }
- }
-}
-
-Local<Object> BSON::GetSerializeObject(const Handle<Value>& argValue)
-{
- Local<Object> object = argValue->ToObject();
- if(object->Has(_toBSONString))
- {
- const Local<Value>& toBSON = object->Get(_toBSONString);
- if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function");
-
- Local<Value> result = Local<Function>::Cast(toBSON)->Call(object, 0, NULL);
- if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object");
- return result->ToObject();
- }
- else
- {
- return object;
- }
-}
-
-Handle<Value> BSON::BSONSerialize(const Arguments &args)
-{
- HandleScope scope;
-
- if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
- if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
- if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
- if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
- if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
-
- // Unpack the BSON parser instance
- BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
-
- // Calculate the total size of the document in binary form to ensure we only allocate memory once
- // With serialize function
- bool serializeFunctions = (args.Length() >= 4) && args[3]->BooleanValue();
-
- char *serialized_object = NULL;
- size_t object_size;
- try
- {
- Local<Object> object = bson->GetSerializeObject(args[0]);
-
- BSONSerializer<CountStream> counter(bson, false, serializeFunctions);
- counter.SerializeDocument(object);
- object_size = counter.GetSerializeSize();
-
- // Allocate the memory needed for the serialization
- serialized_object = (char *)malloc(object_size);
-
- // Check if we have a boolean value
- bool checkKeys = args.Length() >= 3 && args[1]->IsBoolean() && args[1]->BooleanValue();
- BSONSerializer<DataStream> data(bson, checkKeys, serializeFunctions, serialized_object);
- data.SerializeDocument(object);
- }
- catch(char *err_msg)
- {
- free(serialized_object);
- Handle<Value> error = VException(err_msg);
- free(err_msg);
- return error;
- }
-
- // If we have 3 arguments
- if(args.Length() == 3 || args.Length() == 4)
- {
- Buffer *buffer = Buffer::New(serialized_object, object_size);
- free(serialized_object);
- return scope.Close(buffer->handle_);
- }
- else
- {
- Local<Value> bin_value = Encode(serialized_object, object_size, BINARY)->ToString();
- free(serialized_object);
- return bin_value;
- }
-}
-
-Handle<Value> BSON::CalculateObjectSize(const Arguments &args)
-{
- HandleScope scope;
- // Ensure we have a valid object
- if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
- if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]");
- if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]");
-
- // Unpack the BSON parser instance
- BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
- bool serializeFunctions = (args.Length() >= 2) && args[1]->BooleanValue();
- BSONSerializer<CountStream> countSerializer(bson, false, serializeFunctions);
- countSerializer.SerializeDocument(args[0]);
-
- // Return the object size
- return scope.Close(Uint32::New((uint32_t) countSerializer.GetSerializeSize()));
-}
-
-Handle<Value> BSON::SerializeWithBufferAndIndex(const Arguments &args)
-{
- HandleScope scope;
-
- //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) {
- // Ensure we have the correct values
- if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
- if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]");
- if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]");
-
- uint32_t index;
- size_t object_size;
-
- try
- {
- BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
-
- Local<Object> obj = args[2]->ToObject();
- char* data = Buffer::Data(obj);
- size_t length = Buffer::Length(obj);
-
- index = args[3]->Uint32Value();
- bool checkKeys = args.Length() >= 4 && args[1]->IsBoolean() && args[1]->BooleanValue();
- bool serializeFunctions = (args.Length() == 5) && args[4]->BooleanValue();
-
- BSONSerializer<DataStream> dataSerializer(bson, checkKeys, serializeFunctions, data+index);
- dataSerializer.SerializeDocument(bson->GetSerializeObject(args[0]));
- object_size = dataSerializer.GetSerializeSize();
-
- if(object_size + index > length) return VException("Serious error - overflowed buffer!!");
- }
- catch(char *exception)
- {
- Handle<Value> error = VException(exception);
- free(exception);
- return error;
- }
-
- return scope.Close(Uint32::New((uint32_t) (index + object_size - 1)));
-}
-
-Handle<Value> BSON::BSONDeserializeStream(const Arguments &args)
-{
- HandleScope scope;
-
- // At least 3 arguments required
- if(args.Length() < 5) return VException("Arguments required (Buffer(data), Number(index in data), Number(number of documents to deserialize), Array(results), Number(index in the array), Object(optional))");
-
- // If the number of argumets equals 3
- if(args.Length() >= 5)
- {
- if(!Buffer::HasInstance(args[0])) return VException("First argument must be Buffer instance");
- if(!args[1]->IsUint32()) return VException("Second argument must be a positive index number");
- if(!args[2]->IsUint32()) return VException("Third argument must be a positive number of documents to deserialize");
- if(!args[3]->IsArray()) return VException("Fourth argument must be an array the size of documents to deserialize");
- if(!args[4]->IsUint32()) return VException("Sixth argument must be a positive index number");
- }
-
- // If we have 4 arguments
- if(args.Length() == 6 && !args[5]->IsObject()) return VException("Fifth argument must be an object with options");
-
- // Define pointer to data
- Local<Object> obj = args[0]->ToObject();
- uint32_t numberOfDocuments = args[2]->Uint32Value();
- uint32_t index = args[1]->Uint32Value();
- uint32_t resultIndex = args[4]->Uint32Value();
-
- // Unpack the BSON parser instance
- BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
-
- // Unpack the buffer variable
-#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
- Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
- char* data = buffer->data();
- size_t length = buffer->length();
-#else
- char* data = Buffer::Data(obj);
- size_t length = Buffer::Length(obj);
-#endif
-
- // Fetch the documents
- Local<Object> documents = args[3]->ToObject();
-
- BSONDeserializer deserializer(bson, data+index, length-index);
- for(uint32_t i = 0; i < numberOfDocuments; i++)
- {
- try
- {
- documents->Set(i + resultIndex, deserializer.DeserializeDocument());
- }
- catch (char* exception)
- {
- Handle<Value> error = VException(exception);
- free(exception);
- return error;
- }
- }
-
- // Return new index of parsing
- return scope.Close(Uint32::New((uint32_t) (index + deserializer.GetSerializeSize())));
-}
-
-// Exporting function
-extern "C" void init(Handle<Object> target)
-{
- HandleScope scope;
- BSON::Initialize(target);
-}
-
-NODE_MODULE(bson, BSON::Initialize);
+//===========================================================================
+
+#include <stdarg.h>
+#include <cstdlib>
+#include <cstring>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif
+
+#include <v8.h>
+
+// this and the above block must be around the v8.h header otherwise
+// v8 is not happy
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+
+#include <cmath>
+#include <iostream>
+#include <limits>
+#include <vector>
+
+#include "bson.h"
+
+using namespace v8;
+using namespace node;
+
+//===========================================================================
+
+void DataStream::WriteObjectId(const Handle<Object>& object, const Handle<String>& key)
+{
+ uint16_t buffer[12];
+ object->Get(key)->ToString()->Write(buffer, 0, 12);
+ for(uint32_t i = 0; i < 12; ++i)
+ {
+ *p++ = (char) buffer[i];
+ }
+}
+
+void ThrowAllocatedStringException(size_t allocationSize, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ char* string = (char*) malloc(allocationSize);
+ vsprintf(string, format, args);
+ va_end(args);
+
+ throw string;
+}
+
+void DataStream::CheckKey(const Local<String>& keyName)
+{
+ size_t keyLength = keyName->Utf8Length();
+ if(keyLength == 0) return;
+
+ char* keyStringBuffer = (char*) alloca(keyLength+1);
+ keyName->WriteUtf8(keyStringBuffer);
+
+ if(keyStringBuffer[0] == '$')
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not start with '$'", keyStringBuffer);
+ }
+
+ if(strchr(keyStringBuffer, '.') != NULL)
+ {
+ ThrowAllocatedStringException(64+keyLength, "key %s must not contain '.'", keyStringBuffer);
+ }
+}
+
+template<typename T> void BSONSerializer<T>::SerializeDocument(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+ Local<Object> object = bson->GetSerializeObject(value);
+
+ // Get the object property names
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ Local<Array> propertyNames = object->GetPropertyNames();
+ #else
+ Local<Array> propertyNames = object->GetOwnPropertyNames();
+ #endif
+
+ // Length of the property
+ int propertyLength = propertyNames->Length();
+ for(int i = 0; i < propertyLength; ++i)
+ {
+ const Local<String>& propertyName = propertyNames->Get(i)->ToString();
+ if(checkKeys) this->CheckKey(propertyName);
+
+ const Local<Value>& propertyValue = object->Get(propertyName);
+
+ if(serializeFunctions || !propertyValue->IsFunction())
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteString(propertyName);
+ SerializeValue(typeLocation, propertyValue);
+ }
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+template<typename T> void BSONSerializer<T>::SerializeArray(const Handle<Value>& value)
+{
+ void* documentSize = this->BeginWriteSize();
+
+ Local<Array> array = Local<Array>::Cast(value->ToObject());
+ uint32_t arrayLength = array->Length();
+
+ for(uint32_t i = 0; i < arrayLength; ++i)
+ {
+ void* typeLocation = this->BeginWriteType();
+ this->WriteUInt32String(i);
+ SerializeValue(typeLocation, array->Get(i));
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(documentSize);
+}
+
+// This is templated so that we can use this function to both count the number of bytes, and to serialize those bytes.
+// The template approach eliminates almost all of the inspection of values unless they're required (eg. string lengths)
+// and ensures that there is always consistency between bytes counted and bytes written by design.
+template<typename T> void BSONSerializer<T>::SerializeValue(void* typeLocation, const Handle<Value>& value)
+{
+ if(value->IsNumber())
+ {
+ double doubleValue = value->NumberValue();
+ int intValue = (int) doubleValue;
+ if(intValue == doubleValue)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_INT);
+ this->WriteInt32(intValue);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(doubleValue);
+ }
+ }
+ else if(value->IsString())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_STRING);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsBoolean())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BOOLEAN);
+ this->WriteBool(value);
+ }
+ else if(value->IsArray())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_ARRAY);
+ SerializeArray(value);
+ }
+ else if(value->IsDate())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_DATE);
+ this->WriteInt64(value);
+ }
+ else if(value->IsRegExp())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_REGEXP);
+ const Handle<RegExp>& regExp = Handle<RegExp>::Cast(value);
+
+ this->WriteString(regExp->GetSource());
+
+ int flags = regExp->GetFlags();
+ if(flags & RegExp::kGlobal) this->WriteByte('s');
+ if(flags & RegExp::kIgnoreCase) this->WriteByte('i');
+ if(flags & RegExp::kMultiline) this->WriteByte('m');
+ this->WriteByte(0);
+ }
+ else if(value->IsFunction())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(value->ToString());
+ }
+ else if(value->IsObject())
+ {
+ const Local<Object>& object = value->ToObject();
+ if(object->Has(bson->_bsontypeString))
+ {
+ const Local<String>& constructorString = object->GetConstructorName();
+ if(bson->longString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_LONG);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->timestampString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_TIMESTAMP);
+ this->WriteInt32(object, bson->_longLowString);
+ this->WriteInt32(object, bson->_longHighString);
+ }
+ else if(bson->objectIDString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OID);
+ this->WriteObjectId(object, bson->_objectIDidString);
+ }
+ else if(bson->binaryString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ uint32_t length = object->Get(bson->_binaryPositionString)->Uint32Value();
+ Local<Object> bufferObj = object->Get(bson->_binaryBufferString)->ToObject();
+
+ this->WriteInt32(length);
+ this->WriteByte(object, bson->_binarySubTypeString); // write subtype
+ this->WriteData(Buffer::Data(bufferObj), length);
+ }
+ else if(bson->doubleString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NUMBER);
+ this->WriteDouble(object, bson->_doubleValueString);
+ }
+ else if(bson->symbolString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_SYMBOL);
+ this->WriteLengthPrefixedString(object->Get(bson->_symbolValueString)->ToString());
+ }
+ else if(bson->codeString->StrictEquals(constructorString))
+ {
+ const Local<String>& function = object->Get(bson->_codeCodeString)->ToString();
+ const Local<Object>& scope = object->Get(bson->_codeScopeString)->ToObject();
+
+ // For Node < 0.6.X use the GetPropertyNames
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 6
+ uint32_t propertyNameLength = scope->GetPropertyNames()->Length();
+ #else
+ uint32_t propertyNameLength = scope->GetOwnPropertyNames()->Length();
+ #endif
+
+ if(propertyNameLength > 0)
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE_W_SCOPE);
+ void* codeWidthScopeSize = this->BeginWriteSize();
+ this->WriteLengthPrefixedString(function->ToString());
+ SerializeDocument(scope);
+ this->CommitSize(codeWidthScopeSize);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_CODE);
+ this->WriteLengthPrefixedString(function->ToString());
+ }
+ }
+ else if(bson->dbrefString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+
+ void* dbRefSize = this->BeginWriteSize();
+
+ void* refType = this->BeginWriteType();
+ this->WriteData("$ref", 5);
+ SerializeValue(refType, object->Get(bson->_dbRefNamespaceString));
+
+ void* idType = this->BeginWriteType();
+ this->WriteData("$id", 4);
+ SerializeValue(idType, object->Get(bson->_dbRefOidString));
+
+ const Local<Value>& refDbValue = object->Get(bson->_dbRefDbString);
+ if(!refDbValue->IsUndefined())
+ {
+ void* dbType = this->BeginWriteType();
+ this->WriteData("$db", 4);
+ SerializeValue(dbType, refDbValue);
+ }
+
+ this->WriteByte(0);
+ this->CommitSize(dbRefSize);
+ }
+ else if(bson->minKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MIN_KEY);
+ }
+ else if(bson->maxKeyString->StrictEquals(constructorString))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_MAX_KEY);
+ }
+ }
+ else if(Buffer::HasInstance(value))
+ {
+ this->CommitType(typeLocation, BSON_TYPE_BINARY);
+
+ #if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(value->ToObject());
+ uint32_t length = object->length();
+ #else
+ uint32_t length = Buffer::Length(value->ToObject());
+ #endif
+
+ this->WriteInt32(length);
+ this->WriteByte(0);
+ this->WriteData(Buffer::Data(value->ToObject()), length);
+ }
+ else
+ {
+ this->CommitType(typeLocation, BSON_TYPE_OBJECT);
+ SerializeDocument(value);
+ }
+ }
+ else if(value->IsNull() || value->IsUndefined())
+ {
+ this->CommitType(typeLocation, BSON_TYPE_NULL);
+ }
+}
+
+// Data points to start of element list, length is length of entire document including '\0' but excluding initial size
+BSONDeserializer::BSONDeserializer(BSON* aBson, char* data, size_t length)
+: bson(aBson),
+ pStart(data),
+ p(data),
+ pEnd(data + length - 1)
+{
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+BSONDeserializer::BSONDeserializer(BSONDeserializer& parentSerializer, size_t length)
+: bson(parentSerializer.bson),
+ pStart(parentSerializer.p),
+ p(parentSerializer.p),
+ pEnd(parentSerializer.p + length - 1)
+{
+ parentSerializer.p += length;
+ if(pEnd > parentSerializer.pEnd) ThrowAllocatedStringException(64, "Child document exceeds parent's bounds");
+ if(*pEnd != '\0') ThrowAllocatedStringException(64, "Missing end of document marker '\\0'");
+}
+
+Local<String> BSONDeserializer::ReadCString()
+{
+ char* start = p;
+ while(*p++) { }
+ return String::New(start, (int32_t) (p-start-1) );
+}
+
+int32_t BSONDeserializer::ReadRegexOptions()
+{
+ int32_t options = 0;
+ for(;;)
+ {
+ switch(*p++)
+ {
+ case '\0': return options;
+ case 's': options |= RegExp::kGlobal; break;
+ case 'i': options |= RegExp::kIgnoreCase; break;
+ case 'm': options |= RegExp::kMultiline; break;
+ }
+ }
+}
+
+uint32_t BSONDeserializer::ReadIntegerString()
+{
+ uint32_t value = 0;
+ while(*p)
+ {
+ if(*p < '0' || *p > '9') ThrowAllocatedStringException(64, "Invalid key for array");
+ value = value * 10 + *p++ - '0';
+ }
+ ++p;
+ return value;
+}
+
+Local<String> BSONDeserializer::ReadString()
+{
+ uint32_t length = ReadUInt32();
+ char* start = p;
+ p += length;
+ return String::New(start, length-1);
+}
+
+Local<String> BSONDeserializer::ReadObjectId()
+{
+ uint16_t objectId[12];
+ for(size_t i = 0; i < 12; ++i)
+ {
+ objectId[i] = *reinterpret_cast<unsigned char*>(p++);
+ }
+ return String::New(objectId, 12);
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocument()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeDocumentInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeDocumentInternal()
+{
+ Local<Object> returnObject = Object::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ const Local<String>& name = ReadCString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnObject->ForceSet(name, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Document: Serialize consumed unexpected number of bytes");
+
+ // From JavaScript:
+ // if(object['$id'] != null) object = new DBRef(object['$ref'], object['$id'], object['$db']);
+ if(returnObject->Has(bson->_dbRefIdRefString))
+ {
+ Local<Value> argv[] = { returnObject->Get(bson->_dbRefRefString), returnObject->Get(bson->_dbRefIdRefString), returnObject->Get(bson->_dbRefDbRefString) };
+ return bson->dbrefConstructor->NewInstance(3, argv);
+ }
+ else
+ {
+ return returnObject;
+ }
+}
+
+Handle<Value> BSONDeserializer::DeserializeArray()
+{
+ uint32_t length = ReadUInt32();
+ if(length < 5) ThrowAllocatedStringException(64, "Bad BSON: Array Document is less than 5 bytes");
+
+ BSONDeserializer documentDeserializer(*this, length-4);
+ return documentDeserializer.DeserializeArrayInternal();
+}
+
+Handle<Value> BSONDeserializer::DeserializeArrayInternal()
+{
+ Local<Array> returnArray = Array::New();
+
+ while(HasMoreData())
+ {
+ BsonType type = (BsonType) ReadByte();
+ uint32_t index = ReadIntegerString();
+ const Handle<Value>& value = DeserializeValue(type);
+ returnArray->Set(index, value);
+ }
+ if(p != pEnd) ThrowAllocatedStringException(64, "Bad BSON Array: Serialize consumed unexpected number of bytes");
+
+ return returnArray;
+}
+
+Handle<Value> BSONDeserializer::DeserializeValue(BsonType type)
+{
+ switch(type)
+ {
+ case BSON_TYPE_STRING:
+ return ReadString();
+
+ case BSON_TYPE_INT:
+ return Integer::New(ReadInt32());
+
+ case BSON_TYPE_NUMBER:
+ return Number::New(ReadDouble());
+
+ case BSON_TYPE_NULL:
+ return Null();
+
+ case BSON_TYPE_UNDEFINED:
+ return Undefined();
+
+ case BSON_TYPE_TIMESTAMP:
+ {
+ int32_t lowBits = ReadInt32();
+ int32_t highBits = ReadInt32();
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->timestampConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_BOOLEAN:
+ return (ReadByte() != 0) ? True() : False();
+
+ case BSON_TYPE_REGEXP:
+ {
+ const Local<String>& regex = ReadCString();
+ int32_t options = ReadRegexOptions();
+ return RegExp::New(regex, (RegExp::Flags) options);
+ }
+
+ case BSON_TYPE_CODE:
+ {
+ const Local<Value>& code = ReadString();
+ const Local<Value>& scope = Object::New();
+ Local<Value> argv[] = { code, scope };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_CODE_W_SCOPE:
+ {
+ ReadUInt32();
+ const Local<Value>& code = ReadString();
+ const Handle<Value>& scope = DeserializeDocument();
+ Local<Value> argv[] = { code, scope->ToObject() };
+ return bson->codeConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_OID:
+ {
+ Local<Value> argv[] = { ReadObjectId() };
+ return bson->objectIDConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_BINARY:
+ {
+ uint32_t length = ReadUInt32();
+ uint32_t subType = ReadByte();
+ Buffer* buffer = Buffer::New(p, length);
+ p += length;
+
+ Handle<Value> argv[] = { buffer->handle_, Uint32::New(subType) };
+ return bson->binaryConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_LONG:
+ {
+ // Read 32 bit integers
+ int32_t lowBits = (int32_t) ReadInt32();
+ int32_t highBits = (int32_t) ReadInt32();
+
+ // If value is < 2^53 and >-2^53
+ if((highBits < 0x200000 || (highBits == 0x200000 && lowBits == 0)) && highBits >= -0x200000) {
+ // Adjust the pointer and read as 64 bit value
+ p -= 8;
+ // Read the 64 bit value
+ int64_t finalValue = (int64_t) ReadInt64();
+ return Number::New(finalValue);
+ }
+
+ Local<Value> argv[] = { Int32::New(lowBits), Int32::New(highBits) };
+ return bson->longConstructor->NewInstance(2, argv);
+ }
+
+ case BSON_TYPE_DATE:
+ return Date::New((double) ReadInt64());
+
+ case BSON_TYPE_ARRAY:
+ return DeserializeArray();
+
+ case BSON_TYPE_OBJECT:
+ return DeserializeDocument();
+
+ case BSON_TYPE_SYMBOL:
+ {
+ const Local<String>& string = ReadString();
+ Local<Value> argv[] = { string };
+ return bson->symbolConstructor->NewInstance(1, argv);
+ }
+
+ case BSON_TYPE_MIN_KEY:
+ return bson->minKeyConstructor->NewInstance();
+
+ case BSON_TYPE_MAX_KEY:
+ return bson->maxKeyConstructor->NewInstance();
+
+ default:
+ ThrowAllocatedStringException(64, "Unhandled BSON Type: %d", type);
+ }
+
+ return v8::Null();
+}
+
+
+static Handle<Value> VException(const char *msg)
+{
+ HandleScope scope;
+ return ThrowException(Exception::Error(String::New(msg)));
+}
+
+Persistent<FunctionTemplate> BSON::constructor_template;
+
+BSON::BSON() : ObjectWrap()
+{
+ // Setup pre-allocated comparision objects
+ _bsontypeString = Persistent<String>::New(String::New("_bsontype"));
+ _longLowString = Persistent<String>::New(String::New("low_"));
+ _longHighString = Persistent<String>::New(String::New("high_"));
+ _objectIDidString = Persistent<String>::New(String::New("id"));
+ _binaryPositionString = Persistent<String>::New(String::New("position"));
+ _binarySubTypeString = Persistent<String>::New(String::New("sub_type"));
+ _binaryBufferString = Persistent<String>::New(String::New("buffer"));
+ _doubleValueString = Persistent<String>::New(String::New("value"));
+ _symbolValueString = Persistent<String>::New(String::New("value"));
+ _dbRefRefString = Persistent<String>::New(String::New("$ref"));
+ _dbRefIdRefString = Persistent<String>::New(String::New("$id"));
+ _dbRefDbRefString = Persistent<String>::New(String::New("$db"));
+ _dbRefNamespaceString = Persistent<String>::New(String::New("namespace"));
+ _dbRefDbString = Persistent<String>::New(String::New("db"));
+ _dbRefOidString = Persistent<String>::New(String::New("oid"));
+ _codeCodeString = Persistent<String>::New(String::New("code"));
+ _codeScopeString = Persistent<String>::New(String::New("scope"));
+ _toBSONString = Persistent<String>::New(String::New("toBSON"));
+
+ longString = Persistent<String>::New(String::New("Long"));
+ objectIDString = Persistent<String>::New(String::New("ObjectID"));
+ binaryString = Persistent<String>::New(String::New("Binary"));
+ codeString = Persistent<String>::New(String::New("Code"));
+ dbrefString = Persistent<String>::New(String::New("DBRef"));
+ symbolString = Persistent<String>::New(String::New("Symbol"));
+ doubleString = Persistent<String>::New(String::New("Double"));
+ timestampString = Persistent<String>::New(String::New("Timestamp"));
+ minKeyString = Persistent<String>::New(String::New("MinKey"));
+ maxKeyString = Persistent<String>::New(String::New("MaxKey"));
+}
+
+void BSON::Initialize(v8::Handle<v8::Object> target)
+{
+ // Grab the scope of the call from Node
+ HandleScope scope;
+ // Define a new function template
+ Local<FunctionTemplate> t = FunctionTemplate::New(New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("BSON"));
+
+ // Instance methods
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "calculateObjectSize", CalculateObjectSize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serialize", BSONSerialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "serializeWithBufferAndIndex", SerializeWithBufferAndIndex);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserialize", BSONDeserialize);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "deserializeStream", BSONDeserializeStream);
+
+ target->ForceSet(String::NewSymbol("BSON"), constructor_template->GetFunction());
+}
+
+// Create a new instance of BSON and passing it the existing context
+Handle<Value> BSON::New(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Check that we have an array
+ if(args.Length() == 1 && args[0]->IsArray())
+ {
+ // Cast the array to a local reference
+ Local<Array> array = Local<Array>::Cast(args[0]);
+
+ if(array->Length() > 0)
+ {
+ // Create a bson object instance and return it
+ BSON *bson = new BSON();
+
+ uint32_t foundClassesMask = 0;
+
+ // Iterate over all entries to save the instantiate funtions
+ for(uint32_t i = 0; i < array->Length(); i++)
+ {
+ // Let's get a reference to the function
+ Local<Function> func = Local<Function>::Cast(array->Get(i));
+ Local<String> functionName = func->GetName()->ToString();
+
+ // Save the functions making them persistant handles (they don't get collected)
+ if(functionName->StrictEquals(bson->longString))
+ {
+ bson->longConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 1;
+ }
+ else if(functionName->StrictEquals(bson->objectIDString))
+ {
+ bson->objectIDConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 2;
+ }
+ else if(functionName->StrictEquals(bson->binaryString))
+ {
+ bson->binaryConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 4;
+ }
+ else if(functionName->StrictEquals(bson->codeString))
+ {
+ bson->codeConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 8;
+ }
+ else if(functionName->StrictEquals(bson->dbrefString))
+ {
+ bson->dbrefConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x10;
+ }
+ else if(functionName->StrictEquals(bson->symbolString))
+ {
+ bson->symbolConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x20;
+ }
+ else if(functionName->StrictEquals(bson->doubleString))
+ {
+ bson->doubleConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x40;
+ }
+ else if(functionName->StrictEquals(bson->timestampString))
+ {
+ bson->timestampConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x80;
+ }
+ else if(functionName->StrictEquals(bson->minKeyString))
+ {
+ bson->minKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x100;
+ }
+ else if(functionName->StrictEquals(bson->maxKeyString))
+ {
+ bson->maxKeyConstructor = Persistent<Function>::New(func);
+ foundClassesMask |= 0x200;
+ }
+ }
+
+ // Check if we have the right number of constructors otherwise throw an error
+ if(foundClassesMask != 0x3ff)
+ {
+ delete bson;
+ return VException("Missing function constructor for either [Long/ObjectID/Binary/Code/DbRef/Symbol/Double/Timestamp/MinKey/MaxKey]");
+ }
+ else
+ {
+ bson->Wrap(args.This());
+ return args.This();
+ }
+ }
+ else
+ {
+ return VException("No types passed in");
+ }
+ }
+ else
+ {
+ return VException("Argument passed in must be an array of types");
+ }
+}
+
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+//------------------------------------------------------------------------------------------------
+
+Handle<Value> BSON::BSONDeserialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ // Ensure that we have an parameter
+ if(Buffer::HasInstance(args[0]) && args.Length() > 1) return VException("One argument required - buffer1.");
+ if(args[0]->IsString() && args.Length() > 1) return VException("One argument required - string1.");
+ // Throw an exception if the argument is not of type Buffer
+ if(!Buffer::HasInstance(args[0]) && !args[0]->IsString()) return VException("Argument must be a Buffer or String.");
+
+ // Define pointer to data
+ Local<Object> obj = args[0]->ToObject();
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // If we passed in a buffer, let's unpack it, otherwise let's unpack the string
+ if(Buffer::HasInstance(obj))
+ {
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
+ Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
+ char* data = buffer->data();
+ size_t length = buffer->length();
+#else
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+#endif
+
+ // Validate that we have at least 5 bytes
+ if(length < 5) return VException("corrupt bson message < 5 bytes long");
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, length);
+ return deserializer.DeserializeDocument();
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ return error;
+ }
+
+ }
+ else
+ {
+ // The length of the data for this encoding
+ ssize_t len = DecodeBytes(args[0], BINARY);
+
+ // Validate that we have at least 5 bytes
+ if(len < 5) return VException("corrupt bson message < 5 bytes long");
+
+ // Let's define the buffer size
+ char* data = (char *)malloc(len);
+ DecodeWrite(data, len, args[0], BINARY);
+
+ try
+ {
+ BSONDeserializer deserializer(bson, data, len);
+ Handle<Value> result = deserializer.DeserializeDocument();
+ free(data);
+ return result;
+
+ }
+ catch(char* exception)
+ {
+ Handle<Value> error = VException(exception);
+ free(exception);
+ free(data);
+ return error;
+ }
+ }
+}
+
+Local<Object> BSON::GetSerializeObject(const Handle<Value>& argValue)
+{
+ Local<Object> object = argValue->ToObject();
+ if(object->Has(_toBSONString))
+ {
+ const Local<Value>& toBSON = object->Get(_toBSONString);
+ if(!toBSON->IsFunction()) ThrowAllocatedStringException(64, "toBSON is not a function");
+
+ Local<Value> result = Local<Function>::Cast(toBSON)->Call(object, 0, NULL);
+ if(!result->IsObject()) ThrowAllocatedStringException(64, "toBSON function did not return an object");
+ return result->ToObject();
+ }
+ else
+ {
+ return object;
+ }
+}
+
+Handle<Value> BSON::BSONSerialize(const Arguments &args)
+{
+ HandleScope scope;
+
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 3 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !args[2]->IsBoolean() && !args[3]->IsBoolean()) return VException("One, two or tree arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+ if(args.Length() > 4) return VException("One, two, tree or four arguments required - [object] or [object, boolean] or [object, boolean, boolean] or [object, boolean, boolean, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ // Calculate the total size of the document in binary form to ensure we only allocate memory once
+ // With serialize function
+ bool serializeFunctions = (args.Length() >= 4) && args[3]->BooleanValue();
+
+ char *serialized_object = NULL;
+ size_t object_size;
+ try
+ {
+ Local<Object> object = bson->GetSerializeObject(args[0]);
+
+ BSONSerializer<CountStream> counter(bson, false, serializeFunctions);
+ counter.SerializeDocument(object);
+ object_size = counter.GetSerializeSize();
+
+ // Allocate the memory needed for the serialization
+ serialized_object = (char *)malloc(object_size);
+
+ // Check if we have a boolean value
+ bool checkKeys = args.Length() >= 3 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ BSONSerializer<DataStream> data(bson, checkKeys, serializeFunctions, serialized_object);
+ data.SerializeDocument(object);
+ }
+ catch(char *err_msg)
+ {
+ free(serialized_object);
+ Handle<Value> error = VException(err_msg);
+ free(err_msg);
+ return error;
+ }
+
+ // If we have 3 arguments
+ if(args.Length() == 3 || args.Length() == 4)
+ {
+ Buffer *buffer = Buffer::New(serialized_object, object_size);
+ free(serialized_object);
+ return scope.Close(buffer->handle_);
+ }
+ else
+ {
+ Local<Value> bin_value = Encode(serialized_object, object_size, BINARY)->ToString();
+ free(serialized_object);
+ return bin_value;
+ }
+}
+
+Handle<Value> BSON::CalculateObjectSize(const Arguments &args)
+{
+ HandleScope scope;
+ // Ensure we have a valid object
+ if(args.Length() == 1 && !args[0]->IsObject()) return VException("One argument required - [object]");
+ if(args.Length() == 2 && !args[0]->IsObject() && !args[1]->IsBoolean()) return VException("Two arguments required - [object, boolean]");
+ if(args.Length() > 3) return VException("One or two arguments required - [object] or [object, boolean]");
+
+ // Unpack the BSON parser instance
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+ bool serializeFunctions = (args.Length() >= 2) && args[1]->BooleanValue();
+ BSONSerializer<CountStream> countSerializer(bson, false, serializeFunctions);
+ countSerializer.SerializeDocument(args[0]);
+
+ // Return the object size
+ return scope.Close(Uint32::New((uint32_t) countSerializer.GetSerializeSize()));
+}
+
+Handle<Value> BSON::SerializeWithBufferAndIndex(const Arguments &args)
+{
+ HandleScope scope;
+
+ //BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object, ->, buffer, index) {
+ // Ensure we have the correct values
+ if(args.Length() > 5) return VException("Four or five parameters required [object, boolean, Buffer, int] or [object, boolean, Buffer, int, boolean]");
+ if(args.Length() == 4 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32()) return VException("Four parameters required [object, boolean, Buffer, int]");
+ if(args.Length() == 5 && !args[0]->IsObject() && !args[1]->IsBoolean() && !Buffer::HasInstance(args[2]) && !args[3]->IsUint32() && !args[4]->IsBoolean()) return VException("Four parameters required [object, boolean, Buffer, int, boolean]");
+
+ uint32_t index;
+ size_t object_size;
+
+ try
+ {
+ BSON *bson = ObjectWrap::Unwrap<BSON>(args.This());
+
+ Local<Object> obj = args[2]->ToObject();
+ char* data = Buffer::Data(obj);
+ size_t length = Buffer::Length(obj);
+
+ index = args[3]->Uint32Value();
+ bool checkKeys = args.Length() >= 4 && args[1]->IsBoolean() && args[1]->BooleanValue();
+ bool serializeFunctions = (args.Length() == 5) && args[4]->BooleanValue();
+
+ BSONSerializer<DataStream> dataSerializer(bson, checkKeys, serializeFunctions, data+index);
+ dataSerializer.SerializeDocument(bson->GetSerializeObject(args[0]));
+ object_size = dataSerializer.GetSerializeSize();
+
+ if(object_size + index > length) return VException("Serious error - overflowed buffer!!");
+ }