mirror of
https://github.com/sstent/node.git
synced 2026-03-14 17:05:54 +00:00
big update - restarted app including jquery
This commit is contained in:
113
app/app.js
Normal file
113
app/app.js
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
/**
|
||||
* Module dependencies.
|
||||
*/
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var db = require('mongoskin').db('localhost:27017/test');
|
||||
var testcollection = db.collection('testcollection');
|
||||
var exercisecollection = db.collection('exercisecollection');
|
||||
var expressocollection = db.collection('expressocollection');
|
||||
var hrdatacollection = db.collection('expressocollection');
|
||||
|
||||
var app = require('http').createServer(function handler(request, response) {
|
||||
|
||||
console.log('request starting...;' + request.url);
|
||||
|
||||
var filePath = '.' + request.url;
|
||||
if (filePath == './')
|
||||
filePath = './index.html';
|
||||
|
||||
var extname = path.extname(filePath);
|
||||
var contentType = 'text/html';
|
||||
switch (extname) {
|
||||
case '.js':
|
||||
contentType = 'text/javascript';
|
||||
break;
|
||||
case '.css':
|
||||
contentType = 'text/css';
|
||||
break;
|
||||
}
|
||||
|
||||
path.exists(filePath, function(exists) {
|
||||
|
||||
if (exists) {
|
||||
fs.readFile(filePath, function(error, content) {
|
||||
if (error) {
|
||||
response.writeHead(500);
|
||||
response.end();
|
||||
}
|
||||
else {
|
||||
response.writeHead(200, { 'Content-Type': contentType });
|
||||
response.end(content, 'utf-8');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
response.writeHead(404);
|
||||
response.end();
|
||||
}
|
||||
});
|
||||
}).listen(3000);
|
||||
|
||||
|
||||
var io = require('socket.io');
|
||||
io = io.listen(app);
|
||||
io.configure('development', function(){
|
||||
io.set("transports", ["websocket"]);
|
||||
});
|
||||
|
||||
io.sockets.on('connection', function(socket) {
|
||||
console.log('Client connected');
|
||||
|
||||
// socket.on('getactivites', function(data) {
|
||||
console.log('getactivites')
|
||||
testcollection.find().toArray(function(err, result) {
|
||||
if (err) throw err;
|
||||
socket.emit('populateactivities', result);
|
||||
});
|
||||
// });
|
||||
////////////////////////
|
||||
socket.on('addactivity', function(data) {
|
||||
console.log('addactivity' + JSON.stringify(data))
|
||||
testcollection.insert(data, function(err, result) {
|
||||
if (err) throw err;
|
||||
testcollection.find().toArray(function(err, result) {
|
||||
if (err) throw err;
|
||||
socket.emit('populateactivities', result);
|
||||
});
|
||||
});
|
||||
});
|
||||
/////////////////////
|
||||
socket.on('delactivity', function(id) {
|
||||
testcollection.removeById(id,function(err, reply){
|
||||
if (err) throw err;
|
||||
testcollection.find().toArray(function(err, result) {
|
||||
if (err) throw err;
|
||||
socket.emit('populateactivities', result);
|
||||
});
|
||||
});
|
||||
});
|
||||
///////////////////
|
||||
socket.on('getexercises', function(data) {
|
||||
console.log('getactivites')
|
||||
exercisecollection.find().toArray(function(err, result) {
|
||||
if (err) throw err;
|
||||
socket.emit('populateexercises', result);
|
||||
});
|
||||
});
|
||||
////////////////
|
||||
socket.on('getexpressotracks', function(data) {
|
||||
console.log('getactivites')
|
||||
expressocollection.find().toArray(function(err, result) {
|
||||
if (err) throw err;
|
||||
socket.emit('populateexpresso', result);
|
||||
});
|
||||
});
|
||||
////////////////
|
||||
|
||||
////////////////
|
||||
});
|
||||
|
||||
|
||||
|
||||
260
app/index.html
Normal file
260
app/index.html
Normal file
@@ -0,0 +1,260 @@
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Ninja Store - Items</title>
|
||||
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
|
||||
<script type="text/javascript" src="http://code.jquery.com/ui/1.8.18/jquery-ui.min.js"></script>
|
||||
<script type='text/javascript' src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.9/jquery-ui.js"></script>
|
||||
<script src="/static/javascripts/jsrender.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script src="/static/form2js/form2js.js"></script>
|
||||
<script src="/static/form2js/jquery.toObject.js"></script>
|
||||
<script src="/static/form2js/json2.js"></script>
|
||||
<link rel="stylesheet" href="/static/stylesheets/smoothness/jquery-ui-1.8.20.custom.css"/>
|
||||
<link rel="stylesheet" href="/static/stylesheets/style.css"/>
|
||||
<script id="movieTemplate1" type="text/x-jsrender">
|
||||
<h3>{{:activity.date}} - {{:activity.name}}</h3>
|
||||
<div class="workoutdata">
|
||||
<h4>{{:activity.date}} - {{:activity.name}}</h4>
|
||||
<a href=# class="activitydelete" title="{{:_id}}" >Delete</a>
|
||||
{{if activity.lap}}
|
||||
{{for activity.lap}}
|
||||
<p>LAP {{:#index+1}} -
|
||||
{{if run}} Run - {{:run.name}} - {{:run.distance}}KM in {{:run.time}}{{/if}}
|
||||
{{if bike}} Bike - {{:bike.name}} - {{:bike.distance}} x {{:bike.time}}{{/if}}
|
||||
{{if cardio}} Cardio - {{:cardio.name}} - {{:cardio.distance}} x {{:cardio.time}}{{/if}}
|
||||
{{if exercise}} Exercise - {{:exercise.name}} - {{:exercise.sets}} x {{:exercise.reps}} with {{:exercise.weight}} Kg{{/if}}
|
||||
{{if rest}} Recovery Step {{/if}}
|
||||
</p>
|
||||
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
</script>
|
||||
<script type='text/javascript'>
|
||||
$(document).ready(function() {
|
||||
var socket = io.connect();
|
||||
|
||||
socket.emit('populateactivities', 'please');
|
||||
|
||||
socket.on('populateactivities', function(json) {
|
||||
console.log('#poulate recieved');
|
||||
var content = "";
|
||||
$(".workoutdata").hide();
|
||||
$('#ActivityList').empty();
|
||||
$( "#ActivityList" ).html(
|
||||
$( "#movieTemplate1" ).render( json )
|
||||
);
|
||||
$(".ui-accordion-content").css("display", "block");
|
||||
$("#ActivityList").accordion('destroy').accordion({
|
||||
header: 'h3',
|
||||
active: false,
|
||||
collapsible: true
|
||||
});
|
||||
|
||||
});
|
||||
////populate exercise sortable
|
||||
// socket.on('populateexercises', function(json) {
|
||||
// console.log('#exercises recieved');
|
||||
/// var content = "";
|
||||
// $(".workoutdata").hide();
|
||||
// $('#ActivityList').empty();
|
||||
///// for loop
|
||||
//create html with cvaraible $( "#sortableexercises" ).html("<li class=ui-state-default>" + exercise+"</li>")
|
||||
//append to sortable
|
||||
//end for
|
||||
//create sortable
|
||||
// );
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$('#ActivityList').delegate('a.activitydelete', 'click', function() {
|
||||
console.log('delete clicked' + $(this).attr('title'));
|
||||
socket.emit('delactivity', $(this).attr('title'));
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
|
||||
$("#sortable").sortable({
|
||||
placeholder: "ui-state-highlight",
|
||||
revert: true,
|
||||
stop: function(event, ui) {
|
||||
$('#sortable').trigger('sortupdate')
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
$("#sortable").bind('sortupdate', function(event, ui) {
|
||||
$('#sortable li').each(function(){
|
||||
var itemindex= $(this).index()
|
||||
$(this).children('label.uiindex').html((itemindex +1));
|
||||
$(this).children('input').each(function(){
|
||||
var newname = $(this).attr('name').replace(/\[[0-9]*\]/,'[' + itemindex + ']');
|
||||
$(this).attr("name",newname);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
//Removes slectable element
|
||||
$('ul').on('click', '.delete',function() {
|
||||
$(this).parent().remove();
|
||||
$('#sortable').trigger('sortupdate')
|
||||
});
|
||||
|
||||
|
||||
$( "#tabs" ).tabs();
|
||||
$( "#tabs" ).tabs('select' , 0);
|
||||
//sets buttons to be jquery buttons
|
||||
$("button").button();
|
||||
//sets datepickers
|
||||
$( "#datepicker" ).datepicker();
|
||||
|
||||
$("button").button();
|
||||
//adds selectable element
|
||||
$("button").click(function() {
|
||||
var addtype = $(this).attr('value');
|
||||
console.log('click');
|
||||
var newElem = $('.new-' + addtype).clone().attr('style', 'display: block');
|
||||
$(newElem).removeClass("new-" + addtype);
|
||||
$(newElem).children('input').attr('disabled',false);
|
||||
$(newElem).appendTo('#sortable');
|
||||
$(newElem).sortable( "refresh" );
|
||||
$('#sortable').trigger('sortupdate');
|
||||
});
|
||||
|
||||
$('#Activity').find('input.datepicker').datepicker();
|
||||
$('#Activity').find('input.datepicker').datepicker('setDate', new Date());
|
||||
|
||||
|
||||
|
||||
$('#save').click(function() {
|
||||
var selector= "#myForm"
|
||||
//var formDataFirst = $(selector).toObject({mode: 'first'});
|
||||
var formDataAll = $(selector).toObject({mode: 'all'});
|
||||
socket.emit('addactivity', formDataAll);
|
||||
|
||||
console.log('All ', JSON.stringify(formDataAll, null, ' '));
|
||||
// to prevent the page from changing
|
||||
$('ul#sortable li').remove();
|
||||
$('#Activity').find('input').attr('value','');
|
||||
$( "#tabs" ).tabs( "select" , 0 )
|
||||
$('#Activity').find('input.datepicker').datepicker();
|
||||
$('#Activity').find('input.datepicker').datepicker('setDate', new Date());
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
$('#cancelform').click(function() {
|
||||
$('ul#sortable li').remove();
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#my-text-link').click(function() { // bind click event to link
|
||||
$tabs.tabs('select', 2); // switch to third tab
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="logo"><img src="/images/logo.png"/></div>
|
||||
<div id="display">
|
||||
<ul>
|
||||
|
||||
<li style="display: none" class="new-run ui-state-highlight"><label class="uiindex"></label>
|
||||
<label>Run</label>
|
||||
<input type="text" name="activity.lap[0].run.name" placeholder="Location">
|
||||
<input type="text" name="activity.lap[0].run.time" placeholder="hh:mm:ss">
|
||||
<a href=# class=delete>delete</a></li>
|
||||
|
||||
<li style="display: none" class="new-bike ui-state-highlight"><label class="uiindex"></label>
|
||||
<label>Bike</label>
|
||||
<input type="text" name="activity.lap[0].bike.name" hint="Name" placeholder="Track Name">
|
||||
<input type="text" name="activity.lap[0].bike.distance" placeholder="Distance">
|
||||
<input type="text" name="activity.lap[0].bike.time" placeholder="hh:mm:ss">
|
||||
<a href=# class=delete>delete</a></li>
|
||||
|
||||
<li style="display: none" class="new-cardio ui-state-highlight"><label class="uiindex"></label>
|
||||
<label>Cardio</label>
|
||||
<input type="text" name="activity.lap[0].cardio.name" placeholder="Machine">
|
||||
<input type="text" name="activity.lap[0].cardio.distance" placeholder="Distance">
|
||||
<input type="text" name="activity.lap[0].cardio.time" placeholder="hh:mm:ss">
|
||||
<a href=# class=delete>delete</a></li>
|
||||
|
||||
<li style="display: none" class="new-exercise ui-state-highlight"><label class="uiindex"></label><label>Exercise</label>
|
||||
<input type="text" name="activity.lap[0].exercise.name" placeholder="Exercise Name">
|
||||
<input type="text" name="activity.lap[0].exercise.sets" placeholder="Sets">
|
||||
<input type="text" name="activity.lap[0].exercise.sets" placeholder="Reps">
|
||||
<a href=# class=delete>delete</a></li>
|
||||
|
||||
<li style="display: none" class="new-rest ui-state-highlight"><label class="uiindex"></label>
|
||||
<label>Rest</label>
|
||||
<input type="text" name="activity.lap[0].rest[0]" placeholder="Rest">
|
||||
<a href=# class=delete>delete</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="tabs">
|
||||
<ul>
|
||||
<li><a href="#Activities">Activities</a></li>
|
||||
<li><a href="#Activity">Add Activity</a></li>
|
||||
<li><a href="#ExerciseEditor">Edit Exercises</a></li>
|
||||
<li><a href="#ExpressoEditor">Edit Expresso Tracks</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
<div id="Activity">
|
||||
<button class="Add" value="run">Add Run</button>
|
||||
<button class="Add" value="bike">Add Bike</button>
|
||||
<button class="Add" value="exercise">Add Exercise</button>
|
||||
<button class="Add" value="cardio">Add Cardio</button>
|
||||
<button class="Add" value="rest">Add Rest</button>
|
||||
<form id="myForm">
|
||||
<ul id="activityheader">
|
||||
<li><label>Activity Name</label><input type="text" name="activity.name" placeholder="Location"><label>Date</label><input type="text" class="datepicker" name="activity.date"></li>
|
||||
</ul>
|
||||
<ul id="sortable">
|
||||
</ul>
|
||||
<button type="submit" id="save" value="Save">Save</button>
|
||||
<button type="button" id="cancelform" value="Cancel"/>Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="ExerciseEditor" >
|
||||
<button type="button" class="cancel" value="Cancel"/>Cancel</button>
|
||||
CODE FOR EDITING EXERCISES
|
||||
<ul id="sortableexercises">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="ExpressoEditor" >
|
||||
<button type="button" class="cancel" value="Cancel"/>Cancel</button>
|
||||
CODE FOR EDITING EXPRESSO TRACKS
|
||||
<ul id="sortableexpresso">
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="Activities">
|
||||
<ul id="ActivityList"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div></body>
|
||||
</html>
|
||||
216
app/index_backup.html
Normal file
216
app/index_backup.html
Normal file
@@ -0,0 +1,216 @@
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<title>Ninja Store - Items</title>
|
||||
<link rel="stylesheet" href="/static/stylesheets/style.css"/>
|
||||
<script src="/static/javascripts/jquery-1.7.2.min.js"></script>
|
||||
<script src="/static/javascripts/jquery-ui-1.8.21.custom.min.js"></script>
|
||||
<script src="/static/javascripts/jsrender.js"></script>
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script src="/static/form2js/form2js.js"></script>
|
||||
<script src="/static/form2js/jquery.toObject.js"></script>
|
||||
<script src="/static/form2js/json2.js"></script>
|
||||
<script id="movieTemplate1" type="text/x-jsrender">
|
||||
<tr>
|
||||
<td><p class=RowDelete id={{:_id}}>Delete</p></td>
|
||||
<td class=RowShow id={{:_id}} colspan=3>{{:activity.name}}</td>
|
||||
<td>{{:date}}</td>
|
||||
<td>
|
||||
{{if activity.note}}
|
||||
{{for activity.note}}
|
||||
<div>
|
||||
<em>{{:name}}</em>
|
||||
</div>
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
{{if activity.exercise}}
|
||||
{{for activity.exercise}}
|
||||
<div>
|
||||
<em>{{:name}}</em><em>{{:sets}}</em><em>{{:reps}}</em><em>{{:weight}}</em>
|
||||
</div>
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
</script>
|
||||
<script type='text/javascript'>
|
||||
$(document).ready(function() {
|
||||
var socket = io.connect();
|
||||
|
||||
socket.emit('populateactivities', 'please');
|
||||
|
||||
socket.on('populateactivities', function(json) {
|
||||
console.log('#poulate recieved');
|
||||
var content = "";
|
||||
$('#employees').empty();
|
||||
$( "#employees" ).html(
|
||||
$( "#movieTemplate1" ).render( json )
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('#AddAct').click(function() {
|
||||
$('#Activity').attr('style', 'display: block');
|
||||
var last_item = $('.ActivityBlock').length;
|
||||
//if last_item = 0
|
||||
var newElem = $('.ActivityBlock_T').clone(true, true).attr('style', 'display: block');
|
||||
$(newElem).attr('class', 'ActivityBlock');
|
||||
$(newElem).attr('id', 'ActivityBlock' + (last_item + 1) );
|
||||
//$(newElem).children('.AddNeut').attr('data-activity','ActivityBlock_' + (last_item + 1));
|
||||
//$(newElem).children('.RemNeut').attr('data-activity','ActivityBlock_' + (last_item + 1));
|
||||
$(newElem).children('.AddNeut').attr('disabled',false);
|
||||
//$(newElem).children('.RemNeut').attr('disabled',false);
|
||||
$(newElem).find('ul.activity li').children('input').attr('disabled',false);
|
||||
$(newElem).find('ul.activity li').attr('style', 'display: block');
|
||||
$(newElem).find('input.datefield').datepicker()
|
||||
$(newElem).find('input.datefield').datepicker('setDate', new Date())
|
||||
$(newElem).appendTo('form#myForm');
|
||||
|
||||
});
|
||||
|
||||
//Add more fields dynamically.
|
||||
$('input.AddNeut').click(function() {
|
||||
var field = $(this).attr('data-field');
|
||||
var area = $(this).attr('data-area');
|
||||
var limit = $(this).attr('data-limit');
|
||||
var actblock = $(this).closest('div').attr('id');
|
||||
var last_item = $('#' + actblock + ' .' + area ).length;
|
||||
console.log($(this).closest('div').attr('id'))
|
||||
console.log('#' + actblock + ' ul.' + field + ' li:first - LastItem - ',last_item, 'next_Item - ', (last_item + 1) );
|
||||
// create the new element via clone(), and manipulate it's ID using newNum value
|
||||
var newElem = $('#' + actblock + ' ul.' + area + ' li:first').clone().attr('style', 'display: block');
|
||||
$(newElem).attr('class', area);
|
||||
$(newElem).children('input').attr('disabled',false);
|
||||
$(newElem).children('input').each(function(){
|
||||
var newName = $(this).attr('name').replace('[i]','[' +(last_item) + ']');
|
||||
console.log('name ' + newName);
|
||||
$(this).attr('name', newName);
|
||||
});
|
||||
$(newElem).appendTo('div#' + actblock + ' ul.' +area);
|
||||
console.log('enable #' + actblock + ' .'+ area + 'rem');
|
||||
$('#' + actblock + ' .'+ area + 'rem').attr('disabled',false);
|
||||
});
|
||||
|
||||
$('input.RemNeut').click(function() {
|
||||
var field = $(this).attr('data-field');
|
||||
var area = $(this).attr('data-area');
|
||||
var limit = $(this).attr('data-limit');
|
||||
var actblock = $(this).closest('div').attr('id');
|
||||
var last_item = $('#' + actblock + ' .' + area ).length;
|
||||
console.log('.' + area + ' li')
|
||||
console.log('LastItem - ',last_item, 'next_Item - ', (last_item - 1) );
|
||||
if (last_item != 1) {
|
||||
$('#' + actblock + ' ul.' + area + ' li:last').remove();
|
||||
};
|
||||
// enable the "add" button
|
||||
$('.AddNeut#' + area).attr('disabled',false);
|
||||
|
||||
// if only one element remains, disable the "remove" button
|
||||
if (last_item == 2)
|
||||
$('#' + actblock + ' .'+ area + 'rem').attr('disabled','disabled');
|
||||
|
||||
console.log('#'+ area + ' .RemNeut')
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
$('#save').click(function() {
|
||||
var selector= ".ActivityBlock"
|
||||
//var formDataFirst = $(selector).toObject({mode: 'first'});
|
||||
var formDataAll = $(selector).toObject({mode: 'all'});
|
||||
socket.emit('data', formDataAll);
|
||||
|
||||
console.log('All ', JSON.stringify(formDataAll, null, ' '));
|
||||
// to prevent the page from changing
|
||||
$('.ActivityBlock').remove();
|
||||
$('#Activity').attr('style', 'display: none');
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$('#cancel').click(function() {
|
||||
$('.ActivityBlock').remove();
|
||||
$('#Activity').attr('style', 'display: none');
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$("button").button();
|
||||
|
||||
|
||||
});
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="container">
|
||||
<div id="logo"><img src="/images/logo.png"/></div>
|
||||
<div id="display">
|
||||
<div>
|
||||
<button id="AddAct">Add Activity</button>
|
||||
<div id="Activity" style="display: none">
|
||||
<form id="myForm">
|
||||
<input type="submit" id="save" value="Save"/>
|
||||
<input type="button" id="cancel" value="Cancel"/>
|
||||
<div Class="ActivityBlock_T" style="display: none">
|
||||
<input type="button" value="Add Note" data-field="note_area" data-area="note" data-limit="1" class="AddNeut"/>
|
||||
<input type="button" value="Add Exercise" data-field="exercise_area" data-area="exercise" data-limit="10" class="AddNeut"/>
|
||||
<input type="button" value="Add Run" data-field="run_area" data-area="run" data-limit="5" class="AddNeut"/>
|
||||
<input type="button" value="Add Bike" data-field="bike_area" data-area="bike" data-limit="5" class="AddNeut"/>
|
||||
<input type="button" value="Remove Note" data-field="note_area" data-area="note" data-limit="0" disabled="disabled" class="RemNeut noterem"/>
|
||||
<input type="button" value="Remove Exercise" data-field="exercise_area" data-area="exercise" data-limit="0" disabled="disabled" class="RemNeut exerciserem"/>
|
||||
<input type="button" value="Remove Run" data-field="exercise_area" data-area="exercise" data-limit="0" disabled="disabled" class="RemNeut runrem"/>
|
||||
<input type="button" value="Remove Bike" data-field="exercise_area" data-area="exercise" data-limit="0" disabled="disabled" class="RemNeut bikerem"/>
|
||||
<ul class="activity">
|
||||
<li style="display: none" class="activity">
|
||||
<label>Activity</label>
|
||||
<input type="text" name="activity.name" value="Name" disabled="disabled"/>
|
||||
<input type="text" disabled="disabled" class="datefield"/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="note">
|
||||
<li style="display: none" class="note_T">
|
||||
<label>Note</label>
|
||||
<input type="text" name="activity.note[i]" value="Note" disabled="disabled"/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="exercise">
|
||||
<li style="display: none" class="exercise_T">
|
||||
<label>Exercise </label>
|
||||
<input type="text" name="activity.exercise[i].name" value="Name" disabled="disabled"/>
|
||||
<input type="text" name="activity.exercise[i].sets" value="Sets" disabled="disabled" class="numericonly"/>
|
||||
<input type="text" name="activity.exercise[i].reps" value="Reps" disabled="disabled"/>
|
||||
<input type="text" name="activity.exercise[i].weight" value="Weight" disabled="disabled"/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="run">
|
||||
<li style="display: none" class="run_T">
|
||||
<label>Run </label>
|
||||
<input type="text" name="activity.run[i].time" value="Time" disabled="disabled"/>
|
||||
<input type="text" name="activity.run[i].distance" value="Distance" disabled="disabled"/>
|
||||
<input type="text" name="activity.run[i].location" value="Location" disabled="disabled"/>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="bike">
|
||||
<li style="display: none" class="bike_T">
|
||||
<label>Bike </label>
|
||||
<input type="text" name="activity.bike[i].track" value="Track" disabled="disabled"/>
|
||||
<input type="text" name="activity.bike[i].time" value="Time" disabled="disabled" class="numericonly"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<ul id="employees"></ul>
|
||||
</div>
|
||||
</div></body>
|
||||
</html>
|
||||
4
app/node_modules/formidable/.npmignore
generated
vendored
Normal file
4
app/node_modules/formidable/.npmignore
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
/test/tmp/
|
||||
*.upload
|
||||
*.un~
|
||||
*.http
|
||||
4
app/node_modules/formidable/.travis.yml
generated
vendored
Normal file
4
app/node_modules/formidable/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.6
|
||||
14
app/node_modules/formidable/Makefile
generated
vendored
Normal file
14
app/node_modules/formidable/Makefile
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
SHELL := /bin/bash
|
||||
|
||||
test:
|
||||
@./test/run.js
|
||||
|
||||
build: npm test
|
||||
|
||||
npm:
|
||||
npm install .
|
||||
|
||||
clean:
|
||||
rm test/tmp/*
|
||||
|
||||
.PHONY: test clean build
|
||||
311
app/node_modules/formidable/Readme.md
generated
vendored
Normal file
311
app/node_modules/formidable/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,311 @@
|
||||
# Formidable
|
||||
|
||||
[](http://travis-ci.org/felixge/node-formidable)
|
||||
|
||||
## Purpose
|
||||
|
||||
A node.js module for parsing form data, especially file uploads.
|
||||
|
||||
## Current status
|
||||
|
||||
This module was developed for [Transloadit](http://transloadit.com/), a service focused on uploading
|
||||
and encoding images and videos. It has been battle-tested against hundreds of GB of file uploads from
|
||||
a large variety of clients and is considered production-ready.
|
||||
|
||||
## Features
|
||||
|
||||
* Fast (~500mb/sec), non-buffering multipart parser
|
||||
* Automatically writing file uploads to disk
|
||||
* Low memory footprint
|
||||
* Graceful error handling
|
||||
* Very high test coverage
|
||||
|
||||
## Changelog
|
||||
|
||||
### v1.0.9
|
||||
|
||||
* Emit progress when content length header parsed (Tim Koschützki)
|
||||
* Fix Readme syntax due to GitHub changes (goob)
|
||||
* Replace references to old 'sys' module in Readme with 'util' (Peter Sugihara)
|
||||
|
||||
### v1.0.8
|
||||
|
||||
* Strip potentially unsafe characters when using `keepExtensions: true`.
|
||||
* Switch to utest / urun for testing
|
||||
* Add travis build
|
||||
|
||||
### v1.0.7
|
||||
|
||||
* Remove file from package that was causing problems when installing on windows. (#102)
|
||||
* Fix typos in Readme (Jason Davies).
|
||||
|
||||
### v1.0.6
|
||||
|
||||
* Do not default to the default to the field name for file uploads where
|
||||
filename="".
|
||||
|
||||
### v1.0.5
|
||||
|
||||
* Support filename="" in multipart parts
|
||||
* Explain unexpected end() errors in parser better
|
||||
|
||||
**Note:** Starting with this version, formidable emits 'file' events for empty
|
||||
file input fields. Previously those were incorrectly emitted as regular file
|
||||
input fields with value = "".
|
||||
|
||||
### v1.0.4
|
||||
|
||||
* Detect a good default tmp directory regardless of platform. (#88)
|
||||
|
||||
### v1.0.3
|
||||
|
||||
* Fix problems with utf8 characters (#84) / semicolons in filenames (#58)
|
||||
* Small performance improvements
|
||||
* New test suite and fixture system
|
||||
|
||||
### v1.0.2
|
||||
|
||||
* Exclude node\_modules folder from git
|
||||
* Implement new `'aborted'` event
|
||||
* Fix files in example folder to work with recent node versions
|
||||
* Make gently a devDependency
|
||||
|
||||
[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.1...v1.0.2)
|
||||
|
||||
### v1.0.1
|
||||
|
||||
* Fix package.json to refer to proper main directory. (#68, Dean Landolt)
|
||||
|
||||
[See Commits](https://github.com/felixge/node-formidable/compare/v1.0.0...v1.0.1)
|
||||
|
||||
### v1.0.0
|
||||
|
||||
* Add support for multipart boundaries that are quoted strings. (Jeff Craig)
|
||||
|
||||
This marks the beginning of development on version 2.0 which will include
|
||||
several architectural improvements.
|
||||
|
||||
[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.11...v1.0.0)
|
||||
|
||||
### v0.9.11
|
||||
|
||||
* Emit `'progress'` event when receiving data, regardless of parsing it. (Tim Koschützki)
|
||||
* Use [W3C FileAPI Draft](http://dev.w3.org/2006/webapi/FileAPI/) properties for File class
|
||||
|
||||
**Important:** The old property names of the File class will be removed in a
|
||||
future release.
|
||||
|
||||
[See Commits](https://github.com/felixge/node-formidable/compare/v0.9.10...v0.9.11)
|
||||
|
||||
### Older releases
|
||||
|
||||
These releases were done before starting to maintain the above Changelog:
|
||||
|
||||
* [v0.9.10](https://github.com/felixge/node-formidable/compare/v0.9.9...v0.9.10)
|
||||
* [v0.9.9](https://github.com/felixge/node-formidable/compare/v0.9.8...v0.9.9)
|
||||
* [v0.9.8](https://github.com/felixge/node-formidable/compare/v0.9.7...v0.9.8)
|
||||
* [v0.9.7](https://github.com/felixge/node-formidable/compare/v0.9.6...v0.9.7)
|
||||
* [v0.9.6](https://github.com/felixge/node-formidable/compare/v0.9.5...v0.9.6)
|
||||
* [v0.9.5](https://github.com/felixge/node-formidable/compare/v0.9.4...v0.9.5)
|
||||
* [v0.9.4](https://github.com/felixge/node-formidable/compare/v0.9.3...v0.9.4)
|
||||
* [v0.9.3](https://github.com/felixge/node-formidable/compare/v0.9.2...v0.9.3)
|
||||
* [v0.9.2](https://github.com/felixge/node-formidable/compare/v0.9.1...v0.9.2)
|
||||
* [v0.9.1](https://github.com/felixge/node-formidable/compare/v0.9.0...v0.9.1)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.9.0](https://github.com/felixge/node-formidable/compare/v0.8.0...v0.9.0)
|
||||
* [v0.1.0](https://github.com/felixge/node-formidable/commits/v0.1.0)
|
||||
|
||||
## Installation
|
||||
|
||||
Via [npm](http://github.com/isaacs/npm):
|
||||
|
||||
npm install formidable@latest
|
||||
|
||||
Manually:
|
||||
|
||||
git clone git://github.com/felixge/node-formidable.git formidable
|
||||
vim my.js
|
||||
# var formidable = require('./formidable');
|
||||
|
||||
Note: Formidable requires [gently](http://github.com/felixge/node-gently) to run the unit tests, but you won't need it for just using the library.
|
||||
|
||||
## Example
|
||||
|
||||
Parse an incoming file upload.
|
||||
|
||||
var formidable = require('formidable'),
|
||||
http = require('http'),
|
||||
|
||||
util = require('util');
|
||||
|
||||
http.createServer(function(req, res) {
|
||||
if (req.url == '/upload' && req.method.toLowerCase() == 'post') {
|
||||
// parse a file upload
|
||||
var form = new formidable.IncomingForm();
|
||||
form.parse(req, function(err, fields, files) {
|
||||
res.writeHead(200, {'content-type': 'text/plain'});
|
||||
res.write('received upload:\n\n');
|
||||
res.end(util.inspect({fields: fields, files: files}));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// show a file upload form
|
||||
res.writeHead(200, {'content-type': 'text/html'});
|
||||
res.end(
|
||||
'<form action="/upload" enctype="multipart/form-data" method="post">'+
|
||||
'<input type="text" name="title"><br>'+
|
||||
'<input type="file" name="upload" multiple="multiple"><br>'+
|
||||
'<input type="submit" value="Upload">'+
|
||||
'</form>'
|
||||
);
|
||||
}).listen(80);
|
||||
|
||||
## API
|
||||
|
||||
### formidable.IncomingForm
|
||||
|
||||
__new formidable.IncomingForm()__
|
||||
|
||||
Creates a new incoming form.
|
||||
|
||||
__incomingForm.encoding = 'utf-8'__
|
||||
|
||||
The encoding to use for incoming form fields.
|
||||
|
||||
__incomingForm.uploadDir = process.env.TMP || '/tmp' || process.cwd()__
|
||||
|
||||
The directory for placing file uploads in. You can move them later on using
|
||||
`fs.rename()`. The default directory is picked at module load time depending on
|
||||
the first existing directory from those listed above.
|
||||
|
||||
__incomingForm.keepExtensions = false__
|
||||
|
||||
If you want the files written to `incomingForm.uploadDir` to include the extensions of the original files, set this property to `true`.
|
||||
|
||||
__incomingForm.type__
|
||||
|
||||
Either 'multipart' or 'urlencoded' depending on the incoming request.
|
||||
|
||||
__incomingForm.maxFieldsSize = 2 * 1024 * 1024__
|
||||
|
||||
Limits the amount of memory a field (not file) can allocate in bytes.
|
||||
If this value is exceeded, an `'error'` event is emitted. The default
|
||||
size is 2MB.
|
||||
|
||||
__incomingForm.hash = false__
|
||||
|
||||
If you want checksums calculated for incoming files, set this to either `'sha1'` or `'md5'`.
|
||||
|
||||
__incomingForm.bytesReceived__
|
||||
|
||||
The amount of bytes received for this form so far.
|
||||
|
||||
__incomingForm.bytesExpected__
|
||||
|
||||
The expected number of bytes in this form.
|
||||
|
||||
__incomingForm.parse(request, [cb])__
|
||||
|
||||
Parses an incoming node.js `request` containing form data. If `cb` is provided, all fields an files are collected and passed to the callback:
|
||||
|
||||
incomingForm.parse(req, function(err, fields, files) {
|
||||
// ...
|
||||
});
|
||||
|
||||
__incomingForm.onPart(part)__
|
||||
|
||||
You may overwrite this method if you are interested in directly accessing the multipart stream. Doing so will disable any `'field'` / `'file'` events processing which would occur otherwise, making you fully responsible for handling the processing.
|
||||
|
||||
incomingForm.onPart = function(part) {
|
||||
part.addListener('data', function() {
|
||||
// ...
|
||||
});
|
||||
}
|
||||
|
||||
If you want to use formidable to only handle certain parts for you, you can do so:
|
||||
|
||||
incomingForm.onPart = function(part) {
|
||||
if (!part.filename) {
|
||||
// let formidable handle all non-file parts
|
||||
incomingForm.handlePart(part);
|
||||
}
|
||||
}
|
||||
|
||||
Check the code in this method for further inspiration.
|
||||
|
||||
__Event: 'progress' (bytesReceived, bytesExpected)__
|
||||
|
||||
Emitted after each incoming chunk of data that has been parsed. Can be used to roll your own progress bar.
|
||||
|
||||
__Event: 'field' (name, value)__
|
||||
|
||||
Emitted whenever a field / value pair has been received.
|
||||
|
||||
__Event: 'fileBegin' (name, file)__
|
||||
|
||||
Emitted whenever a new file is detected in the upload stream. Use this even if
|
||||
you want to stream the file to somewhere else while buffering the upload on
|
||||
the file system.
|
||||
|
||||
__Event: 'file' (name, file)__
|
||||
|
||||
Emitted whenever a field / file pair has been received. `file` is an instance of `File`.
|
||||
|
||||
__Event: 'error' (err)__
|
||||
|
||||
Emitted when there is an error processing the incoming form. A request that experiences an error is automatically paused, you will have to manually call `request.resume()` if you want the request to continue firing `'data'` events.
|
||||
|
||||
__Event: 'aborted'__
|
||||
|
||||
Emitted when the request was aborted by the user. Right now this can be due to a 'timeout' or 'close' event on the socket. In the future there will be a separate 'timeout' event (needs a change in the node core).
|
||||
|
||||
__Event: 'end' ()__
|
||||
|
||||
Emitted when the entire request has been received, and all contained files have finished flushing to disk. This is a great place for you to send your response.
|
||||
|
||||
### formidable.File
|
||||
|
||||
__file.size = 0__
|
||||
|
||||
The size of the uploaded file in bytes. If the file is still being uploaded (see `'fileBegin'` event), this property says how many bytes of the file have been written to disk yet.
|
||||
|
||||
__file.path = null__
|
||||
|
||||
The path this file is being written to. You can modify this in the `'fileBegin'` event in
|
||||
case you are unhappy with the way formidable generates a temporary path for your files.
|
||||
|
||||
__file.name = null__
|
||||
|
||||
The name this file had according to the uploading client.
|
||||
|
||||
__file.type = null__
|
||||
|
||||
The mime type of this file, according to the uploading client.
|
||||
|
||||
__file.lastModifiedDate = null__
|
||||
|
||||
A date object (or `null`) containing the time this file was last written to. Mostly
|
||||
here for compatibility with the [W3C File API Draft](http://dev.w3.org/2006/webapi/FileAPI/).
|
||||
|
||||
__file.hash = null__
|
||||
|
||||
If hash calculation was set, you can read the hex digest out of this var.
|
||||
|
||||
## License
|
||||
|
||||
Formidable is licensed under the MIT license.
|
||||
|
||||
## Ports
|
||||
|
||||
* [multipart-parser](http://github.com/FooBarWidget/multipart-parser): a C++ parser based on formidable
|
||||
|
||||
## Credits
|
||||
|
||||
* [Ryan Dahl](http://twitter.com/ryah) for his work on [http-parser](http://github.com/ry/http-parser) which heavily inspired multipart_parser.js
|
||||
3
app/node_modules/formidable/TODO
generated
vendored
Normal file
3
app/node_modules/formidable/TODO
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
- Better bufferMaxSize handling approach
|
||||
- Add tests for JSON parser pull request and merge it
|
||||
- Implement QuerystringParser the same way as MultipartParser
|
||||
70
app/node_modules/formidable/benchmark/bench-multipart-parser.js
generated
vendored
Normal file
70
app/node_modules/formidable/benchmark/bench-multipart-parser.js
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
require('../test/common');
|
||||
var multipartParser = require('../lib/multipart_parser'),
|
||||
MultipartParser = multipartParser.MultipartParser,
|
||||
parser = new MultipartParser(),
|
||||
Buffer = require('buffer').Buffer,
|
||||
boundary = '-----------------------------168072824752491622650073',
|
||||
mb = 100,
|
||||
buffer = createMultipartBuffer(boundary, mb * 1024 * 1024),
|
||||
callbacks =
|
||||
{ partBegin: -1,
|
||||
partEnd: -1,
|
||||
headerField: -1,
|
||||
headerValue: -1,
|
||||
partData: -1,
|
||||
end: -1,
|
||||
};
|
||||
|
||||
|
||||
parser.initWithBoundary(boundary);
|
||||
parser.onHeaderField = function() {
|
||||
callbacks.headerField++;
|
||||
};
|
||||
|
||||
parser.onHeaderValue = function() {
|
||||
callbacks.headerValue++;
|
||||
};
|
||||
|
||||
parser.onPartBegin = function() {
|
||||
callbacks.partBegin++;
|
||||
};
|
||||
|
||||
parser.onPartData = function() {
|
||||
callbacks.partData++;
|
||||
};
|
||||
|
||||
parser.onPartEnd = function() {
|
||||
callbacks.partEnd++;
|
||||
};
|
||||
|
||||
parser.onEnd = function() {
|
||||
callbacks.end++;
|
||||
};
|
||||
|
||||
var start = +new Date(),
|
||||
nparsed = parser.write(buffer),
|
||||
duration = +new Date - start,
|
||||
mbPerSec = (mb / (duration / 1000)).toFixed(2);
|
||||
|
||||
console.log(mbPerSec+' mb/sec');
|
||||
|
||||
assert.equal(nparsed, buffer.length);
|
||||
|
||||
function createMultipartBuffer(boundary, size) {
|
||||
var head =
|
||||
'--'+boundary+'\r\n'
|
||||
+ 'content-disposition: form-data; name="field1"\r\n'
|
||||
+ '\r\n'
|
||||
, tail = '\r\n--'+boundary+'--\r\n'
|
||||
, buffer = new Buffer(size);
|
||||
|
||||
buffer.write(head, 'ascii', 0);
|
||||
buffer.write(tail, 'ascii', buffer.length - tail.length);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
process.on('exit', function() {
|
||||
for (var k in callbacks) {
|
||||
assert.equal(0, callbacks[k], k+' count off by '+callbacks[k]);
|
||||
}
|
||||
});
|
||||
43
app/node_modules/formidable/example/post.js
generated
vendored
Normal file
43
app/node_modules/formidable/example/post.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
require('../test/common');
|
||||
var http = require('http'),
|
||||
util = require('util'),
|
||||
formidable = require('formidable'),
|
||||
server;
|
||||
|
||||
server = http.createServer(function(req, res) {
|
||||
if (req.url == '/') {
|
||||
res.writeHead(200, {'content-type': 'text/html'});
|
||||
res.end(
|
||||
'<form action="/post" method="post">'+
|
||||
'<input type="text" name="title"><br>'+
|
||||
'<input type="text" name="data[foo][]"><br>'+
|
||||
'<input type="submit" value="Submit">'+
|
||||
'</form>'
|
||||
);
|
||||
} else if (req.url == '/post') {
|
||||
var form = new formidable.IncomingForm(),
|
||||
fields = [];
|
||||
|
||||
form
|
||||
.on('error', function(err) {
|
||||
res.writeHead(200, {'content-type': 'text/plain'});
|
||||
res.end('error:\n\n'+util.inspect(err));
|
||||
})
|
||||
.on('field', function(field, value) {
|
||||
console.log(field, value);
|
||||
fields.push([field, value]);
|
||||
})
|
||||
.on('end', function() {
|
||||
console.log('-> post done');
|
||||
res.writeHead(200, {'content-type': 'text/plain'});
|
||||
res.end('received fields:\n\n '+util.inspect(fields));
|
||||
});
|
||||
form.parse(req);
|
||||
} else {
|
||||
res.writeHead(404, {'content-type': 'text/plain'});
|
||||
res.end('404');
|
||||
}
|
||||
});
|
||||
server.listen(TEST_PORT);
|
||||
|
||||
console.log('listening on http://localhost:'+TEST_PORT+'/');
|
||||
48
app/node_modules/formidable/example/upload.js
generated
vendored
Normal file
48
app/node_modules/formidable/example/upload.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
require('../test/common');
|
||||
var http = require('http'),
|
||||
util = require('util'),
|
||||
formidable = require('formidable'),
|
||||
server;
|
||||
|
||||
server = http.createServer(function(req, res) {
|
||||
if (req.url == '/') {
|
||||
res.writeHead(200, {'content-type': 'text/html'});
|
||||
res.end(
|
||||
'<form action="/upload" enctype="multipart/form-data" method="post">'+
|
||||
'<input type="text" name="title"><br>'+
|
||||
'<input type="file" name="upload" multiple="multiple"><br>'+
|
||||
'<input type="submit" value="Upload">'+
|
||||
'</form>'
|
||||
);
|
||||
} else if (req.url == '/upload') {
|
||||
var form = new formidable.IncomingForm(),
|
||||
files = [],
|
||||
fields = [];
|
||||
|
||||
form.uploadDir = TEST_TMP;
|
||||
|
||||
form
|
||||
.on('field', function(field, value) {
|
||||
console.log(field, value);
|
||||
fields.push([field, value]);
|
||||
})
|
||||
.on('file', function(field, file) {
|
||||
console.log(field, file);
|
||||
files.push([field, file]);
|
||||
})
|
||||
.on('end', function() {
|
||||
console.log('-> upload done');
|
||||
res.writeHead(200, {'content-type': 'text/plain'});
|
||||
res.write('received fields:\n\n '+util.inspect(fields));
|
||||
res.write('\n\n');
|
||||
res.end('received files:\n\n '+util.inspect(files));
|
||||
});
|
||||
form.parse(req);
|
||||
} else {
|
||||
res.writeHead(404, {'content-type': 'text/plain'});
|
||||
res.end('404');
|
||||
}
|
||||
});
|
||||
server.listen(TEST_PORT);
|
||||
|
||||
console.log('listening on http://localhost:'+TEST_PORT+'/');
|
||||
1
app/node_modules/formidable/index.js
generated
vendored
Normal file
1
app/node_modules/formidable/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/formidable');
|
||||
73
app/node_modules/formidable/lib/file.js
generated
vendored
Normal file
73
app/node_modules/formidable/lib/file.js
generated
vendored
Normal file
@@ -0,0 +1,73 @@
|
||||
if (global.GENTLY) require = GENTLY.hijack(require);
|
||||
|
||||
var util = require('./util'),
|
||||
WriteStream = require('fs').WriteStream,
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
crypto = require('crypto');
|
||||
|
||||
function File(properties) {
|
||||
EventEmitter.call(this);
|
||||
|
||||
this.size = 0;
|
||||
this.path = null;
|
||||
this.name = null;
|
||||
this.type = null;
|
||||
this.hash = null;
|
||||
this.lastModifiedDate = null;
|
||||
|
||||
this._writeStream = null;
|
||||
|
||||
for (var key in properties) {
|
||||
this[key] = properties[key];
|
||||
}
|
||||
|
||||
if(typeof this.hash === 'string') {
|
||||
this.hash = crypto.createHash(properties.hash);
|
||||
}
|
||||
|
||||
this._backwardsCompatibility();
|
||||
}
|
||||
module.exports = File;
|
||||
util.inherits(File, EventEmitter);
|
||||
|
||||
// @todo Next release: Show error messages when accessing these
|
||||
File.prototype._backwardsCompatibility = function() {
|
||||
var self = this;
|
||||
this.__defineGetter__('length', function() {
|
||||
return self.size;
|
||||
});
|
||||
this.__defineGetter__('filename', function() {
|
||||
return self.name;
|
||||
});
|
||||
this.__defineGetter__('mime', function() {
|
||||
return self.type;
|
||||
});
|
||||
};
|
||||
|
||||
File.prototype.open = function() {
|
||||
this._writeStream = new WriteStream(this.path);
|
||||
};
|
||||
|
||||
File.prototype.write = function(buffer, cb) {
|
||||
var self = this;
|
||||
this._writeStream.write(buffer, function() {
|
||||
if(self.hash) {
|
||||
self.hash.update(buffer);
|
||||
}
|
||||
self.lastModifiedDate = new Date();
|
||||
self.size += buffer.length;
|
||||
self.emit('progress', self.size);
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
File.prototype.end = function(cb) {
|
||||
var self = this;
|
||||
this._writeStream.end(function() {
|
||||
if(self.hash) {
|
||||
self.hash = self.hash.digest('hex');
|
||||
}
|
||||
self.emit('end');
|
||||
cb();
|
||||
});
|
||||
};
|
||||
384
app/node_modules/formidable/lib/incoming_form.js
generated
vendored
Normal file
384
app/node_modules/formidable/lib/incoming_form.js
generated
vendored
Normal file
@@ -0,0 +1,384 @@
|
||||
if (global.GENTLY) require = GENTLY.hijack(require);
|
||||
|
||||
var fs = require('fs');
|
||||
var util = require('./util'),
|
||||
path = require('path'),
|
||||
File = require('./file'),
|
||||
MultipartParser = require('./multipart_parser').MultipartParser,
|
||||
QuerystringParser = require('./querystring_parser').QuerystringParser,
|
||||
StringDecoder = require('string_decoder').StringDecoder,
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
Stream = require('stream').Stream;
|
||||
|
||||
function IncomingForm(opts) {
|
||||
if (!(this instanceof IncomingForm)) return new IncomingForm;
|
||||
EventEmitter.call(this);
|
||||
|
||||
opts=opts||{};
|
||||
|
||||
this.error = null;
|
||||
this.ended = false;
|
||||
|
||||
this.maxFieldsSize = opts.maxFieldsSize || 2 * 1024 * 1024;
|
||||
this.keepExtensions = opts.keepExtensions || false;
|
||||
this.uploadDir = opts.uploadDir || IncomingForm.UPLOAD_DIR;
|
||||
this.encoding = opts.encoding || 'utf-8';
|
||||
this.headers = null;
|
||||
this.type = null;
|
||||
this.hash = false;
|
||||
|
||||
this.bytesReceived = null;
|
||||
this.bytesExpected = null;
|
||||
|
||||
this._parser = null;
|
||||
this._flushing = 0;
|
||||
this._fieldsSize = 0;
|
||||
};
|
||||
util.inherits(IncomingForm, EventEmitter);
|
||||
exports.IncomingForm = IncomingForm;
|
||||
|
||||
IncomingForm.UPLOAD_DIR = (function() {
|
||||
var dirs = [process.env.TMP, '/tmp', process.cwd()];
|
||||
for (var i = 0; i < dirs.length; i++) {
|
||||
var dir = dirs[i];
|
||||
var isDirectory = false;
|
||||
|
||||
try {
|
||||
isDirectory = fs.statSync(dir).isDirectory();
|
||||
} catch (e) {}
|
||||
|
||||
if (isDirectory) return dir;
|
||||
}
|
||||
})();
|
||||
|
||||
IncomingForm.prototype.parse = function(req, cb) {
|
||||
this.pause = function() {
|
||||
try {
|
||||
req.pause();
|
||||
} catch (err) {
|
||||
// the stream was destroyed
|
||||
if (!this.ended) {
|
||||
// before it was completed, crash & burn
|
||||
this._error(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.resume = function() {
|
||||
try {
|
||||
req.resume();
|
||||
} catch (err) {
|
||||
// the stream was destroyed
|
||||
if (!this.ended) {
|
||||
// before it was completed, crash & burn
|
||||
this._error(err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
this.writeHeaders(req.headers);
|
||||
|
||||
var self = this;
|
||||
req
|
||||
.on('error', function(err) {
|
||||
self._error(err);
|
||||
})
|
||||
.on('aborted', function() {
|
||||
self.emit('aborted');
|
||||
})
|
||||
.on('data', function(buffer) {
|
||||
self.write(buffer);
|
||||
})
|
||||
.on('end', function() {
|
||||
if (self.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
var err = self._parser.end();
|
||||
if (err) {
|
||||
self._error(err);
|
||||
}
|
||||
});
|
||||
|
||||
if (cb) {
|
||||
var fields = {}, files = {};
|
||||
this
|
||||
.on('field', function(name, value) {
|
||||
fields[name] = value;
|
||||
})
|
||||
.on('file', function(name, file) {
|
||||
files[name] = file;
|
||||
})
|
||||
.on('error', function(err) {
|
||||
cb(err, fields, files);
|
||||
})
|
||||
.on('end', function() {
|
||||
cb(null, fields, files);
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
IncomingForm.prototype.writeHeaders = function(headers) {
|
||||
this.headers = headers;
|
||||
this._parseContentLength();
|
||||
this._parseContentType();
|
||||
};
|
||||
|
||||
IncomingForm.prototype.write = function(buffer) {
|
||||
if (!this._parser) {
|
||||
this._error(new Error('unintialized parser'));
|
||||
return;
|
||||
}
|
||||
|
||||
this.bytesReceived += buffer.length;
|
||||
this.emit('progress', this.bytesReceived, this.bytesExpected);
|
||||
|
||||
var bytesParsed = this._parser.write(buffer);
|
||||
if (bytesParsed !== buffer.length) {
|
||||
this._error(new Error('parser error, '+bytesParsed+' of '+buffer.length+' bytes parsed'));
|
||||
}
|
||||
|
||||
return bytesParsed;
|
||||
};
|
||||
|
||||
IncomingForm.prototype.pause = function() {
|
||||
// this does nothing, unless overwritten in IncomingForm.parse
|
||||
return false;
|
||||
};
|
||||
|
||||
IncomingForm.prototype.resume = function() {
|
||||
// this does nothing, unless overwritten in IncomingForm.parse
|
||||
return false;
|
||||
};
|
||||
|
||||
IncomingForm.prototype.onPart = function(part) {
|
||||
// this method can be overwritten by the user
|
||||
this.handlePart(part);
|
||||
};
|
||||
|
||||
IncomingForm.prototype.handlePart = function(part) {
|
||||
var self = this;
|
||||
|
||||
if (part.filename === undefined) {
|
||||
var value = ''
|
||||
, decoder = new StringDecoder(this.encoding);
|
||||
|
||||
part.on('data', function(buffer) {
|
||||
self._fieldsSize += buffer.length;
|
||||
if (self._fieldsSize > self.maxFieldsSize) {
|
||||
self._error(new Error('maxFieldsSize exceeded, received '+self._fieldsSize+' bytes of field data'));
|
||||
return;
|
||||
}
|
||||
value += decoder.write(buffer);
|
||||
});
|
||||
|
||||
part.on('end', function() {
|
||||
self.emit('field', part.name, value);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this._flushing++;
|
||||
|
||||
var file = new File({
|
||||
path: this._uploadPath(part.filename),
|
||||
name: part.filename,
|
||||
type: part.mime,
|
||||
hash: self.hash
|
||||
});
|
||||
|
||||
this.emit('fileBegin', part.name, file);
|
||||
|
||||
file.open();
|
||||
|
||||
part.on('data', function(buffer) {
|
||||
self.pause();
|
||||
file.write(buffer, function() {
|
||||
self.resume();
|
||||
});
|
||||
});
|
||||
|
||||
part.on('end', function() {
|
||||
file.end(function() {
|
||||
self._flushing--;
|
||||
self.emit('file', part.name, file);
|
||||
self._maybeEnd();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
IncomingForm.prototype._parseContentType = function() {
|
||||
if (!this.headers['content-type']) {
|
||||
this._error(new Error('bad content-type header, no content-type'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.headers['content-type'].match(/urlencoded/i)) {
|
||||
this._initUrlencoded();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.headers['content-type'].match(/multipart/i)) {
|
||||
var m;
|
||||
if (m = this.headers['content-type'].match(/boundary=(?:"([^"]+)"|([^;]+))/i)) {
|
||||
this._initMultipart(m[1] || m[2]);
|
||||
} else {
|
||||
this._error(new Error('bad content-type header, no multipart boundary'));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this._error(new Error('bad content-type header, unknown content-type: '+this.headers['content-type']));
|
||||
};
|
||||
|
||||
IncomingForm.prototype._error = function(err) {
|
||||
if (this.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.error = err;
|
||||
this.pause();
|
||||
this.emit('error', err);
|
||||
};
|
||||
|
||||
IncomingForm.prototype._parseContentLength = function() {
|
||||
if (this.headers['content-length']) {
|
||||
this.bytesReceived = 0;
|
||||
this.bytesExpected = parseInt(this.headers['content-length'], 10);
|
||||
this.emit('progress', this.bytesReceived, this.bytesExpected);
|
||||
}
|
||||
};
|
||||
|
||||
IncomingForm.prototype._newParser = function() {
|
||||
return new MultipartParser();
|
||||
};
|
||||
|
||||
IncomingForm.prototype._initMultipart = function(boundary) {
|
||||
this.type = 'multipart';
|
||||
|
||||
var parser = new MultipartParser(),
|
||||
self = this,
|
||||
headerField,
|
||||
headerValue,
|
||||
part;
|
||||
|
||||
parser.initWithBoundary(boundary);
|
||||
|
||||
parser.onPartBegin = function() {
|
||||
part = new Stream();
|
||||
part.readable = true;
|
||||
part.headers = {};
|
||||
part.name = null;
|
||||
part.filename = null;
|
||||
part.mime = null;
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
};
|
||||
|
||||
parser.onHeaderField = function(b, start, end) {
|
||||
headerField += b.toString(self.encoding, start, end);
|
||||
};
|
||||
|
||||
parser.onHeaderValue = function(b, start, end) {
|
||||
headerValue += b.toString(self.encoding, start, end);
|
||||
};
|
||||
|
||||
parser.onHeaderEnd = function() {
|
||||
headerField = headerField.toLowerCase();
|
||||
part.headers[headerField] = headerValue;
|
||||
|
||||
var m;
|
||||
if (headerField == 'content-disposition') {
|
||||
if (m = headerValue.match(/name="([^"]+)"/i)) {
|
||||
part.name = m[1];
|
||||
}
|
||||
|
||||
part.filename = self._fileName(headerValue);
|
||||
} else if (headerField == 'content-type') {
|
||||
part.mime = headerValue;
|
||||
}
|
||||
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
};
|
||||
|
||||
parser.onHeadersEnd = function() {
|
||||
self.onPart(part);
|
||||
};
|
||||
|
||||
parser.onPartData = function(b, start, end) {
|
||||
part.emit('data', b.slice(start, end));
|
||||
};
|
||||
|
||||
parser.onPartEnd = function() {
|
||||
part.emit('end');
|
||||
};
|
||||
|
||||
parser.onEnd = function() {
|
||||
self.ended = true;
|
||||
self._maybeEnd();
|
||||
};
|
||||
|
||||
this._parser = parser;
|
||||
};
|
||||
|
||||
IncomingForm.prototype._fileName = function(headerValue) {
|
||||
var m = headerValue.match(/filename="(.*?)"($|; )/i)
|
||||
if (!m) return;
|
||||
|
||||
var filename = m[1].substr(m[1].lastIndexOf('\\') + 1);
|
||||
filename = filename.replace(/%22/g, '"');
|
||||
filename = filename.replace(/&#([\d]{4});/g, function(m, code) {
|
||||
return String.fromCharCode(code);
|
||||
});
|
||||
return filename;
|
||||
};
|
||||
|
||||
IncomingForm.prototype._initUrlencoded = function() {
|
||||
this.type = 'urlencoded';
|
||||
|
||||
var parser = new QuerystringParser()
|
||||
, self = this;
|
||||
|
||||
parser.onField = function(key, val) {
|
||||
self.emit('field', key, val);
|
||||
};
|
||||
|
||||
parser.onEnd = function() {
|
||||
self.ended = true;
|
||||
self._maybeEnd();
|
||||
};
|
||||
|
||||
this._parser = parser;
|
||||
};
|
||||
|
||||
IncomingForm.prototype._uploadPath = function(filename) {
|
||||
var name = '';
|
||||
for (var i = 0; i < 32; i++) {
|
||||
name += Math.floor(Math.random() * 16).toString(16);
|
||||
}
|
||||
|
||||
if (this.keepExtensions) {
|
||||
var ext = path.extname(filename);
|
||||
ext = ext.replace(/(\.[a-z0-9]+).*/, '$1')
|
||||
|
||||
name += ext;
|
||||
}
|
||||
|
||||
return path.join(this.uploadDir, name);
|
||||
};
|
||||
|
||||
IncomingForm.prototype._maybeEnd = function() {
|
||||
if (!this.ended || this._flushing) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.emit('end');
|
||||
};
|
||||
3
app/node_modules/formidable/lib/index.js
generated
vendored
Normal file
3
app/node_modules/formidable/lib/index.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
var IncomingForm = require('./incoming_form').IncomingForm;
|
||||
IncomingForm.IncomingForm = IncomingForm;
|
||||
module.exports = IncomingForm;
|
||||
312
app/node_modules/formidable/lib/multipart_parser.js
generated
vendored
Normal file
312
app/node_modules/formidable/lib/multipart_parser.js
generated
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
var Buffer = require('buffer').Buffer,
|
||||
s = 0,
|
||||
S =
|
||||
{ PARSER_UNINITIALIZED: s++,
|
||||
START: s++,
|
||||
START_BOUNDARY: s++,
|
||||
HEADER_FIELD_START: s++,
|
||||
HEADER_FIELD: s++,
|
||||
HEADER_VALUE_START: s++,
|
||||
HEADER_VALUE: s++,
|
||||
HEADER_VALUE_ALMOST_DONE: s++,
|
||||
HEADERS_ALMOST_DONE: s++,
|
||||
PART_DATA_START: s++,
|
||||
PART_DATA: s++,
|
||||
PART_END: s++,
|
||||
END: s++,
|
||||
},
|
||||
|
||||
f = 1,
|
||||
F =
|
||||
{ PART_BOUNDARY: f,
|
||||
LAST_BOUNDARY: f *= 2,
|
||||
},
|
||||
|
||||
LF = 10,
|
||||
CR = 13,
|
||||
SPACE = 32,
|
||||
HYPHEN = 45,
|
||||
COLON = 58,
|
||||
A = 97,
|
||||
Z = 122,
|
||||
|
||||
lower = function(c) {
|
||||
return c | 0x20;
|
||||
};
|
||||
|
||||
for (var s in S) {
|
||||
exports[s] = S[s];
|
||||
}
|
||||
|
||||
function MultipartParser() {
|
||||
this.boundary = null;
|
||||
this.boundaryChars = null;
|
||||
this.lookbehind = null;
|
||||
this.state = S.PARSER_UNINITIALIZED;
|
||||
|
||||
this.index = null;
|
||||
this.flags = 0;
|
||||
};
|
||||
exports.MultipartParser = MultipartParser;
|
||||
|
||||
MultipartParser.stateToString = function(stateNumber) {
|
||||
for (var state in S) {
|
||||
var number = S[state];
|
||||
if (number === stateNumber) return state;
|
||||
}
|
||||
};
|
||||
|
||||
MultipartParser.prototype.initWithBoundary = function(str) {
|
||||
this.boundary = new Buffer(str.length+4);
|
||||
this.boundary.write('\r\n--', 'ascii', 0);
|
||||
this.boundary.write(str, 'ascii', 4);
|
||||
this.lookbehind = new Buffer(this.boundary.length+8);
|
||||
this.state = S.START;
|
||||
|
||||
this.boundaryChars = {};
|
||||
for (var i = 0; i < this.boundary.length; i++) {
|
||||
this.boundaryChars[this.boundary[i]] = true;
|
||||
}
|
||||
};
|
||||
|
||||
MultipartParser.prototype.write = function(buffer) {
|
||||
var self = this,
|
||||
i = 0,
|
||||
len = buffer.length,
|
||||
prevIndex = this.index,
|
||||
index = this.index,
|
||||
state = this.state,
|
||||
flags = this.flags,
|
||||
lookbehind = this.lookbehind,
|
||||
boundary = this.boundary,
|
||||
boundaryChars = this.boundaryChars,
|
||||
boundaryLength = this.boundary.length,
|
||||
boundaryEnd = boundaryLength - 1,
|
||||
bufferLength = buffer.length,
|
||||
c,
|
||||
cl,
|
||||
|
||||
mark = function(name) {
|
||||
self[name+'Mark'] = i;
|
||||
},
|
||||
clear = function(name) {
|
||||
delete self[name+'Mark'];
|
||||
},
|
||||
callback = function(name, buffer, start, end) {
|
||||
if (start !== undefined && start === end) {
|
||||
return;
|
||||
}
|
||||
|
||||
var callbackSymbol = 'on'+name.substr(0, 1).toUpperCase()+name.substr(1);
|
||||
if (callbackSymbol in self) {
|
||||
self[callbackSymbol](buffer, start, end);
|
||||
}
|
||||
},
|
||||
dataCallback = function(name, clear) {
|
||||
var markSymbol = name+'Mark';
|
||||
if (!(markSymbol in self)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clear) {
|
||||
callback(name, buffer, self[markSymbol], buffer.length);
|
||||
self[markSymbol] = 0;
|
||||
} else {
|
||||
callback(name, buffer, self[markSymbol], i);
|
||||
delete self[markSymbol];
|
||||
}
|
||||
};
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
c = buffer[i];
|
||||
switch (state) {
|
||||
case S.PARSER_UNINITIALIZED:
|
||||
return i;
|
||||
case S.START:
|
||||
index = 0;
|
||||
state = S.START_BOUNDARY;
|
||||
case S.START_BOUNDARY:
|
||||
if (index == boundary.length - 2) {
|
||||
if (c != CR) {
|
||||
return i;
|
||||
}
|
||||
index++;
|
||||
break;
|
||||
} else if (index - 1 == boundary.length - 2) {
|
||||
if (c != LF) {
|
||||
return i;
|
||||
}
|
||||
index = 0;
|
||||
callback('partBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
}
|
||||
|
||||
if (c != boundary[index+2]) {
|
||||
return i;
|
||||
}
|
||||
index++;
|
||||
break;
|
||||
case S.HEADER_FIELD_START:
|
||||
state = S.HEADER_FIELD;
|
||||
mark('headerField');
|
||||
index = 0;
|
||||
case S.HEADER_FIELD:
|
||||
if (c == CR) {
|
||||
clear('headerField');
|
||||
state = S.HEADERS_ALMOST_DONE;
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
if (c == HYPHEN) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (c == COLON) {
|
||||
if (index == 1) {
|
||||
// empty header field
|
||||
return i;
|
||||
}
|
||||
dataCallback('headerField', true);
|
||||
state = S.HEADER_VALUE_START;
|
||||
break;
|
||||
}
|
||||
|
||||
cl = lower(c);
|
||||
if (cl < A || cl > Z) {
|
||||
return i;
|
||||
}
|
||||
break;
|
||||
case S.HEADER_VALUE_START:
|
||||
if (c == SPACE) {
|
||||
break;
|
||||
}
|
||||
|
||||
mark('headerValue');
|
||||
state = S.HEADER_VALUE;
|
||||
case S.HEADER_VALUE:
|
||||
if (c == CR) {
|
||||
dataCallback('headerValue', true);
|
||||
callback('headerEnd');
|
||||
state = S.HEADER_VALUE_ALMOST_DONE;
|
||||
}
|
||||
break;
|
||||
case S.HEADER_VALUE_ALMOST_DONE:
|
||||
if (c != LF) {
|
||||
return i;
|
||||
}
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
case S.HEADERS_ALMOST_DONE:
|
||||
if (c != LF) {
|
||||
return i;
|
||||
}
|
||||
|
||||
callback('headersEnd');
|
||||
state = S.PART_DATA_START;
|
||||
break;
|
||||
case S.PART_DATA_START:
|
||||
state = S.PART_DATA
|
||||
mark('partData');
|
||||
case S.PART_DATA:
|
||||
prevIndex = index;
|
||||
|
||||
if (index == 0) {
|
||||
// boyer-moore derrived algorithm to safely skip non-boundary data
|
||||
i += boundaryEnd;
|
||||
while (i < bufferLength && !(buffer[i] in boundaryChars)) {
|
||||
i += boundaryLength;
|
||||
}
|
||||
i -= boundaryEnd;
|
||||
c = buffer[i];
|
||||
}
|
||||
|
||||
if (index < boundary.length) {
|
||||
if (boundary[index] == c) {
|
||||
if (index == 0) {
|
||||
dataCallback('partData', true);
|
||||
}
|
||||
index++;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index == boundary.length) {
|
||||
index++;
|
||||
if (c == CR) {
|
||||
// CR = part boundary
|
||||
flags |= F.PART_BOUNDARY;
|
||||
} else if (c == HYPHEN) {
|
||||
// HYPHEN = end boundary
|
||||
flags |= F.LAST_BOUNDARY;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else if (index - 1 == boundary.length) {
|
||||
if (flags & F.PART_BOUNDARY) {
|
||||
index = 0;
|
||||
if (c == LF) {
|
||||
// unset the PART_BOUNDARY flag
|
||||
flags &= ~F.PART_BOUNDARY;
|
||||
callback('partEnd');
|
||||
callback('partBegin');
|
||||
state = S.HEADER_FIELD_START;
|
||||
break;
|
||||
}
|
||||
} else if (flags & F.LAST_BOUNDARY) {
|
||||
if (c == HYPHEN) {
|
||||
callback('partEnd');
|
||||
callback('end');
|
||||
state = S.END;
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
} else {
|
||||
index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (index > 0) {
|
||||
// when matching a possible boundary, keep a lookbehind reference
|
||||
// in case it turns out to be a false lead
|
||||
lookbehind[index-1] = c;
|
||||
} else if (prevIndex > 0) {
|
||||
// if our boundary turned out to be rubbish, the captured lookbehind
|
||||
// belongs to partData
|
||||
callback('partData', lookbehind, 0, prevIndex);
|
||||
prevIndex = 0;
|
||||
mark('partData');
|
||||
|
||||
// reconsider the current character even so it interrupted the sequence
|
||||
// it could be the beginning of a new sequence
|
||||
i--;
|
||||
}
|
||||
|
||||
break;
|
||||
case S.END:
|
||||
break;
|
||||
default:
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
dataCallback('headerField');
|
||||
dataCallback('headerValue');
|
||||
dataCallback('partData');
|
||||
|
||||
this.index = index;
|
||||
this.state = state;
|
||||
this.flags = flags;
|
||||
|
||||
return len;
|
||||
};
|
||||
|
||||
MultipartParser.prototype.end = function() {
|
||||
if (this.state != S.END) {
|
||||
return new Error('MultipartParser.end(): stream ended unexpectedly: ' + this.explain());
|
||||
}
|
||||
};
|
||||
|
||||
MultipartParser.prototype.explain = function() {
|
||||
return 'state = ' + MultipartParser.stateToString(this.state);
|
||||
};
|
||||
25
app/node_modules/formidable/lib/querystring_parser.js
generated
vendored
Normal file
25
app/node_modules/formidable/lib/querystring_parser.js
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
if (global.GENTLY) require = GENTLY.hijack(require);
|
||||
|
||||
// This is a buffering parser, not quite as nice as the multipart one.
|
||||
// If I find time I'll rewrite this to be fully streaming as well
|
||||
var querystring = require('querystring');
|
||||
|
||||
function QuerystringParser() {
|
||||
this.buffer = '';
|
||||
};
|
||||
exports.QuerystringParser = QuerystringParser;
|
||||
|
||||
QuerystringParser.prototype.write = function(buffer) {
|
||||
this.buffer += buffer.toString('ascii');
|
||||
return buffer.length;
|
||||
};
|
||||
|
||||
QuerystringParser.prototype.end = function() {
|
||||
var fields = querystring.parse(this.buffer);
|
||||
for (var field in fields) {
|
||||
this.onField(field, fields[field]);
|
||||
}
|
||||
this.buffer = '';
|
||||
|
||||
this.onEnd();
|
||||
};
|
||||
6
app/node_modules/formidable/lib/util.js
generated
vendored
Normal file
6
app/node_modules/formidable/lib/util.js
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// Backwards compatibility ...
|
||||
try {
|
||||
module.exports = require('util');
|
||||
} catch (e) {
|
||||
module.exports = require('sys');
|
||||
}
|
||||
4
app/node_modules/formidable/node-gently/Makefile
generated
vendored
Normal file
4
app/node_modules/formidable/node-gently/Makefile
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
test:
|
||||
@find test/simple/test-*.js | xargs -n 1 -t node
|
||||
|
||||
.PHONY: test
|
||||
167
app/node_modules/formidable/node-gently/Readme.md
generated
vendored
Normal file
167
app/node_modules/formidable/node-gently/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,167 @@
|
||||
# Gently
|
||||
|
||||
## Purpose
|
||||
|
||||
A node.js module that helps with stubbing and behavior verification. It allows you to test the most remote and nested corners of your code while keeping being fully unobtrusive.
|
||||
|
||||
## Features
|
||||
|
||||
* Overwrite and stub individual object functions
|
||||
* Verify that all expected calls have been made in the expected order
|
||||
* Restore stubbed functions to their original behavior
|
||||
* Detect object / class names from obj.constructor.name and obj.toString()
|
||||
* Hijack any required module function or class constructor
|
||||
|
||||
## Installation
|
||||
|
||||
Via [npm](http://github.com/isaacs/npm):
|
||||
|
||||
npm install gently@latest
|
||||
|
||||
## Example
|
||||
|
||||
Make sure your dog is working properly:
|
||||
|
||||
function Dog() {}
|
||||
|
||||
Dog.prototype.seeCat = function() {
|
||||
this.bark('whuf, whuf');
|
||||
this.run();
|
||||
}
|
||||
|
||||
Dog.prototype.bark = function(bark) {
|
||||
require('sys').puts(bark);
|
||||
}
|
||||
|
||||
var gently = new (require('gently'))
|
||||
, assert = require('assert')
|
||||
, dog = new Dog();
|
||||
|
||||
gently.expect(dog, 'bark', function(bark) {
|
||||
assert.equal(bark, 'whuf, whuf');
|
||||
});
|
||||
gently.expect(dog, 'run');
|
||||
|
||||
dog.seeCat();
|
||||
|
||||
You can also easily test event emitters with this, for example a simple sequence of 2 events emitted by `fs.WriteStream`:
|
||||
|
||||
var gently = new (require('gently'))
|
||||
, stream = new (require('fs').WriteStream)('my_file.txt');
|
||||
|
||||
gently.expect(stream, 'emit', function(event) {
|
||||
assert.equal(event, 'open');
|
||||
});
|
||||
|
||||
gently.expect(stream, 'emit', function(event) {
|
||||
assert.equal(event, 'drain');
|
||||
});
|
||||
|
||||
For a full read world example, check out this test case: [test-incoming-form.js](http://github.com/felixge/node-formidable/blob/master/test/simple/test-incoming-form.js) (in [node-formdiable](http://github.com/felixge/node-formidable)).
|
||||
|
||||
## API
|
||||
|
||||
### Gently
|
||||
|
||||
#### new Gently()
|
||||
|
||||
Creates a new gently instance. It listens to the process `'exit'` event to make sure all expectations have been verified.
|
||||
|
||||
#### gently.expect(obj, method, [[count], stubFn])
|
||||
|
||||
Creates an expectation for an objects method to be called. You can optionally specify the call `count` you are expecting, as well as `stubFn` function that will run instead of the original function.
|
||||
|
||||
Returns a reference to the function that is getting overwritten.
|
||||
|
||||
#### gently.expect([count], stubFn)
|
||||
|
||||
Returns a function that is supposed to be executed `count` times, delegating any calls to the provided `stubFn` function. Naming your stubFn closure will help to properly diagnose errors that are being thrown:
|
||||
|
||||
childProcess.exec('ls', gently.expect(function lsCallback(code) {
|
||||
assert.equal(0, code);
|
||||
}));
|
||||
|
||||
#### gently.restore(obj, method)
|
||||
|
||||
Restores an object method that has been previously overwritten using `gently.expect()`.
|
||||
|
||||
#### gently.hijack(realRequire)
|
||||
|
||||
Returns a new require functions that catches a reference to all required modules into `gently.hijacked`.
|
||||
|
||||
To use this function, include a line like this in your `'my-module.js'`.
|
||||
|
||||
if (global.GENTLY) require = GENTLY.hijack(require);
|
||||
|
||||
var sys = require('sys');
|
||||
exports.hello = function() {
|
||||
sys.log('world');
|
||||
};
|
||||
|
||||
Now you can write a test for the module above:
|
||||
|
||||
var gently = global.GENTLY = new (require('gently'))
|
||||
, myModule = require('./my-module');
|
||||
|
||||
gently.expect(gently.hijacked.sys, 'log', function(str) {
|
||||
assert.equal(str, 'world');
|
||||
});
|
||||
|
||||
myModule.hello();
|
||||
|
||||
#### gently.stub(location, [exportsName])
|
||||
|
||||
Returns a stub class that will be used instead of the real class from the module at `location` with the given `exportsName`.
|
||||
|
||||
This allows to test an OOP version of the previous example, where `'my-module.js'`.
|
||||
|
||||
if (global.GENTLY) require = GENTLY.hijack(require);
|
||||
|
||||
var World = require('./world');
|
||||
|
||||
exports.hello = function() {
|
||||
var world = new World();
|
||||
world.hello();
|
||||
}
|
||||
|
||||
And `world.js` looks like this:
|
||||
|
||||
var sys = require('sys');
|
||||
|
||||
function World() {
|
||||
|
||||
}
|
||||
module.exports = World;
|
||||
|
||||
World.prototype.hello = function() {
|
||||
sys.log('world');
|
||||
};
|
||||
|
||||
Testing `'my-module.js'` can now easily be accomplished:
|
||||
|
||||
var gently = global.GENTLY = new (require('gently'))
|
||||
, WorldStub = gently.stub('./world')
|
||||
, myModule = require('./my-module')
|
||||
, WORLD;
|
||||
|
||||
gently.expect(WorldStub, 'new', function() {
|
||||
WORLD = this;
|
||||
});
|
||||
|
||||
gently.expect(WORLD, 'hello');
|
||||
|
||||
myModule.hello();
|
||||
|
||||
#### gently.hijacked
|
||||
|
||||
An object that holds the references to all hijacked modules.
|
||||
|
||||
#### gently.verify([msg])
|
||||
|
||||
Verifies that all expectations of this gently instance have been satisfied. If not called manually, this method is called when the process `'exit'` event is fired.
|
||||
|
||||
If `msg` is given, it will appear in any error that might be thrown.
|
||||
|
||||
## License
|
||||
|
||||
Gently is licensed under the MIT license.
|
||||
22
app/node_modules/formidable/node-gently/example/dog.js
generated
vendored
Normal file
22
app/node_modules/formidable/node-gently/example/dog.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
require('../test/common');
|
||||
function Dog() {}
|
||||
|
||||
Dog.prototype.seeCat = function() {
|
||||
this.bark('whuf, whuf');
|
||||
this.run();
|
||||
}
|
||||
|
||||
Dog.prototype.bark = function(bark) {
|
||||
require('sys').puts(bark);
|
||||
}
|
||||
|
||||
var gently = new (require('gently'))
|
||||
, assert = require('assert')
|
||||
, dog = new Dog();
|
||||
|
||||
gently.expect(dog, 'bark', function(bark) {
|
||||
assert.equal(bark, 'whuf, whuf');
|
||||
});
|
||||
gently.expect(dog, 'run');
|
||||
|
||||
dog.seeCat();
|
||||
11
app/node_modules/formidable/node-gently/example/event_emitter.js
generated
vendored
Normal file
11
app/node_modules/formidable/node-gently/example/event_emitter.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
require('../test/common');
|
||||
var gently = new (require('gently'))
|
||||
, stream = new (require('fs').WriteStream)('my_file.txt');
|
||||
|
||||
gently.expect(stream, 'emit', function(event) {
|
||||
assert.equal(event, 'open');
|
||||
});
|
||||
|
||||
gently.expect(stream, 'emit', function(event) {
|
||||
assert.equal(event, 'drain');
|
||||
});
|
||||
1
app/node_modules/formidable/node-gently/index.js
generated
vendored
Normal file
1
app/node_modules/formidable/node-gently/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/gently');
|
||||
184
app/node_modules/formidable/node-gently/lib/gently/gently.js
generated
vendored
Normal file
184
app/node_modules/formidable/node-gently/lib/gently/gently.js
generated
vendored
Normal file
@@ -0,0 +1,184 @@
|
||||
var path = require('path');
|
||||
|
||||
function Gently() {
|
||||
this.expectations = [];
|
||||
this.hijacked = {};
|
||||
|
||||
var self = this;
|
||||
process.addListener('exit', function() {
|
||||
self.verify('process exit');
|
||||
});
|
||||
};
|
||||
module.exports = Gently;
|
||||
|
||||
Gently.prototype.stub = function(location, exportsName) {
|
||||
function Stub() {
|
||||
return Stub['new'].apply(this, arguments);
|
||||
};
|
||||
|
||||
Stub['new'] = function () {};
|
||||
|
||||
var stubName = 'require('+JSON.stringify(location)+')';
|
||||
if (exportsName) {
|
||||
stubName += '.'+exportsName;
|
||||
}
|
||||
|
||||
Stub.prototype.toString = Stub.toString = function() {
|
||||
return stubName;
|
||||
};
|
||||
|
||||
var exports = this.hijacked[location] || {};
|
||||
if (exportsName) {
|
||||
exports[exportsName] = Stub;
|
||||
} else {
|
||||
exports = Stub;
|
||||
}
|
||||
|
||||
this.hijacked[location] = exports;
|
||||
return Stub;
|
||||
};
|
||||
|
||||
Gently.prototype.hijack = function(realRequire) {
|
||||
var self = this;
|
||||
return function(location) {
|
||||
return self.hijacked[location] = (self.hijacked[location])
|
||||
? self.hijacked[location]
|
||||
: realRequire(location);
|
||||
};
|
||||
};
|
||||
|
||||
Gently.prototype.expect = function(obj, method, count, stubFn) {
|
||||
if (typeof obj != 'function' && typeof obj != 'object' && typeof obj != 'number') {
|
||||
throw new Error
|
||||
( 'Bad 1st argument for gently.expect(), '
|
||||
+ 'object, function, or number expected, got: '+(typeof obj)
|
||||
);
|
||||
} else if (typeof obj == 'function' && (typeof method != 'string')) {
|
||||
// expect(stubFn) interface
|
||||
stubFn = obj;
|
||||
obj = null;
|
||||
method = null;
|
||||
count = 1;
|
||||
} else if (typeof method == 'function') {
|
||||
// expect(count, stubFn) interface
|
||||
count = obj;
|
||||
stubFn = method;
|
||||
obj = null;
|
||||
method = null;
|
||||
} else if (typeof count == 'function') {
|
||||
// expect(obj, method, stubFn) interface
|
||||
stubFn = count;
|
||||
count = 1;
|
||||
} else if (count === undefined) {
|
||||
// expect(obj, method) interface
|
||||
count = 1;
|
||||
}
|
||||
|
||||
var name = this._name(obj, method, stubFn);
|
||||
this.expectations.push({obj: obj, method: method, stubFn: stubFn, name: name, count: count});
|
||||
|
||||
var self = this;
|
||||
function delegate() {
|
||||
return self._stubFn(this, obj, method, name, Array.prototype.slice.call(arguments));
|
||||
}
|
||||
|
||||
if (!obj) {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
var original = (obj[method])
|
||||
? obj[method]._original || obj[method]
|
||||
: undefined;
|
||||
|
||||
obj[method] = delegate;
|
||||
return obj[method]._original = original;
|
||||
};
|
||||
|
||||
Gently.prototype.restore = function(obj, method) {
|
||||
if (!obj[method] || !obj[method]._original) {
|
||||
throw new Error(this._name(obj, method)+' is not gently stubbed');
|
||||
}
|
||||
obj[method] = obj[method]._original;
|
||||
};
|
||||
|
||||
Gently.prototype.verify = function(msg) {
|
||||
if (!this.expectations.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var validExpectations = [];
|
||||
for (var i = 0, l = this.expectations.length; i < l; i++) {
|
||||
var expectation = this.expectations[i];
|
||||
|
||||
if (expectation.count > 0) {
|
||||
validExpectations.push(expectation);
|
||||
}
|
||||
}
|
||||
|
||||
this.expectations = []; // reset so that no duplicate verification attempts are made
|
||||
|
||||
if (!validExpectations.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
var expectation = validExpectations[0];
|
||||
|
||||
throw new Error
|
||||
( 'Expected call to '+expectation.name+' did not happen'
|
||||
+ ( (msg)
|
||||
? ' ('+msg+')'
|
||||
: ''
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
Gently.prototype._stubFn = function(self, obj, method, name, args) {
|
||||
var expectation = this.expectations[0], obj, method;
|
||||
|
||||
if (!expectation) {
|
||||
throw new Error('Unexpected call to '+name+', no call was expected');
|
||||
}
|
||||
|
||||
if (expectation.obj !== obj || expectation.method !== method) {
|
||||
throw new Error('Unexpected call to '+name+', expected call to '+ expectation.name);
|
||||
}
|
||||
|
||||
expectation.count -= 1;
|
||||
if (expectation.count === 0) {
|
||||
this.expectations.shift();
|
||||
|
||||
// autorestore original if its not a closure
|
||||
// and no more expectations on that object
|
||||
var has_more_expectations = this.expectations.reduce(function (memo, expectation) {
|
||||
return memo || (expectation.obj === obj && expectation.method === method);
|
||||
}, false);
|
||||
if (obj !== null && method !== null && !has_more_expectations) {
|
||||
if (typeof obj[method]._original !== 'undefined') {
|
||||
obj[method] = obj[method]._original;
|
||||
delete obj[method]._original;
|
||||
} else {
|
||||
delete obj[method];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (expectation.stubFn) {
|
||||
return expectation.stubFn.apply(self, args);
|
||||
}
|
||||
};
|
||||
|
||||
Gently.prototype._name = function(obj, method, stubFn) {
|
||||
if (obj) {
|
||||
var objectName = obj.toString();
|
||||
if (objectName == '[object Object]' && obj.constructor.name) {
|
||||
objectName = '['+obj.constructor.name+']';
|
||||
}
|
||||
return (objectName)+'.'+method+'()';
|
||||
}
|
||||
|
||||
if (stubFn.name) {
|
||||
return stubFn.name+'()';
|
||||
}
|
||||
|
||||
return '>> '+stubFn.toString()+' <<';
|
||||
};
|
||||
1
app/node_modules/formidable/node-gently/lib/gently/index.js
generated
vendored
Normal file
1
app/node_modules/formidable/node-gently/lib/gently/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./gently');
|
||||
14
app/node_modules/formidable/node-gently/package.json
generated
vendored
Normal file
14
app/node_modules/formidable/node-gently/package.json
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "gently",
|
||||
"version": "0.9.2",
|
||||
"directories": {
|
||||
"lib": "./lib/gently"
|
||||
},
|
||||
"main": "./lib/gently/index",
|
||||
"dependencies": {},
|
||||
"devDependencies": {},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"optionalDependencies": {}
|
||||
}
|
||||
8
app/node_modules/formidable/node-gently/test/common.js
generated
vendored
Normal file
8
app/node_modules/formidable/node-gently/test/common.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
var path = require('path')
|
||||
, sys = require('sys');
|
||||
|
||||
require.paths.unshift(path.dirname(__dirname)+'/lib');
|
||||
|
||||
global.puts = sys.puts;
|
||||
global.p = function() {sys.error(sys.inspect.apply(null, arguments))};;
|
||||
global.assert = require('assert');
|
||||
348
app/node_modules/formidable/node-gently/test/simple/test-gently.js
generated
vendored
Normal file
348
app/node_modules/formidable/node-gently/test/simple/test-gently.js
generated
vendored
Normal file
@@ -0,0 +1,348 @@
|
||||
require('../common');
|
||||
var Gently = require('gently')
|
||||
, gently;
|
||||
|
||||
function test(test) {
|
||||
process.removeAllListeners('exit');
|
||||
gently = new Gently();
|
||||
test();
|
||||
}
|
||||
|
||||
test(function constructor() {
|
||||
assert.deepEqual(gently.expectations, []);
|
||||
assert.deepEqual(gently.hijacked, {});
|
||||
assert.equal(gently.constructor.name, 'Gently');
|
||||
});
|
||||
|
||||
test(function expectBadArgs() {
|
||||
var BAD_ARG = 'oh no';
|
||||
try {
|
||||
gently.expect(BAD_ARG);
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Bad 1st argument for gently.expect(), object, function, or number expected, got: '+(typeof BAD_ARG));
|
||||
}
|
||||
});
|
||||
|
||||
test(function expectObjMethod() {
|
||||
var OBJ = {}, NAME = 'foobar';
|
||||
OBJ.foo = function(x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
gently._name = function() {
|
||||
return NAME;
|
||||
};
|
||||
|
||||
var original = OBJ.foo
|
||||
, stubFn = function() {};
|
||||
|
||||
(function testAddOne() {
|
||||
assert.strictEqual(gently.expect(OBJ, 'foo', stubFn), original);
|
||||
|
||||
assert.equal(gently.expectations.length, 1);
|
||||
var expectation = gently.expectations[0];
|
||||
assert.strictEqual(expectation.obj, OBJ);
|
||||
assert.strictEqual(expectation.method, 'foo');
|
||||
assert.strictEqual(expectation.stubFn, stubFn);
|
||||
assert.strictEqual(expectation.name, NAME);
|
||||
assert.strictEqual(OBJ.foo._original, original);
|
||||
})();
|
||||
|
||||
(function testAddTwo() {
|
||||
gently.expect(OBJ, 'foo', 2, stubFn);
|
||||
assert.equal(gently.expectations.length, 2);
|
||||
assert.strictEqual(OBJ.foo._original, original);
|
||||
})();
|
||||
|
||||
(function testAddOneWithoutMock() {
|
||||
gently.expect(OBJ, 'foo');
|
||||
assert.equal(gently.expectations.length, 3);
|
||||
})();
|
||||
|
||||
var stubFnCalled = 0, SELF = {};
|
||||
gently._stubFn = function(self, obj, method, name, args) {
|
||||
stubFnCalled++;
|
||||
assert.strictEqual(self, SELF);
|
||||
assert.strictEqual(obj, OBJ);
|
||||
assert.strictEqual(method, 'foo');
|
||||
assert.strictEqual(name, NAME);
|
||||
assert.deepEqual(args, [1, 2]);
|
||||
return 23;
|
||||
};
|
||||
assert.equal(OBJ.foo.apply(SELF, [1, 2]), 23);
|
||||
assert.equal(stubFnCalled, 1);
|
||||
});
|
||||
|
||||
test(function expectClosure() {
|
||||
var NAME = 'MY CLOSURE';
|
||||
function closureFn() {};
|
||||
|
||||
gently._name = function() {
|
||||
return NAME;
|
||||
};
|
||||
|
||||
var fn = gently.expect(closureFn);
|
||||
assert.equal(gently.expectations.length, 1);
|
||||
var expectation = gently.expectations[0];
|
||||
assert.strictEqual(expectation.obj, null);
|
||||
assert.strictEqual(expectation.method, null);
|
||||
assert.strictEqual(expectation.stubFn, closureFn);
|
||||
assert.strictEqual(expectation.name, NAME);
|
||||
|
||||
var stubFnCalled = 0, SELF = {};
|
||||
gently._stubFn = function(self, obj, method, name, args) {
|
||||
stubFnCalled++;
|
||||
assert.strictEqual(self, SELF);
|
||||
assert.strictEqual(obj, null);
|
||||
assert.strictEqual(method, null);
|
||||
assert.strictEqual(name, NAME);
|
||||
assert.deepEqual(args, [1, 2]);
|
||||
return 23;
|
||||
};
|
||||
assert.equal(fn.apply(SELF, [1, 2]), 23);
|
||||
assert.equal(stubFnCalled, 1);
|
||||
});
|
||||
|
||||
test(function expectClosureCount() {
|
||||
var stubFnCalled = 0;
|
||||
function closureFn() {stubFnCalled++};
|
||||
|
||||
var fn = gently.expect(2, closureFn);
|
||||
assert.equal(gently.expectations.length, 1);
|
||||
fn();
|
||||
assert.equal(gently.expectations.length, 1);
|
||||
fn();
|
||||
assert.equal(stubFnCalled, 2);
|
||||
});
|
||||
|
||||
test(function restore() {
|
||||
var OBJ = {}, NAME = '[my object].myFn()';
|
||||
OBJ.foo = function(x) {
|
||||
return x;
|
||||
};
|
||||
|
||||
gently._name = function() {
|
||||
return NAME;
|
||||
};
|
||||
|
||||
var original = OBJ.foo;
|
||||
gently.expect(OBJ, 'foo');
|
||||
gently.restore(OBJ, 'foo');
|
||||
assert.strictEqual(OBJ.foo, original);
|
||||
|
||||
(function testError() {
|
||||
try {
|
||||
gently.restore(OBJ, 'foo');
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, NAME+' is not gently stubbed');
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
test(function _stubFn() {
|
||||
var OBJ1 = {toString: function() {return '[OBJ 1]'}}
|
||||
, OBJ2 = {toString: function() {return '[OBJ 2]'}, foo: function () {return 'bar';}}
|
||||
, SELF = {};
|
||||
|
||||
gently.expect(OBJ1, 'foo', function(x) {
|
||||
assert.strictEqual(this, SELF);
|
||||
return x * 2;
|
||||
});
|
||||
|
||||
assert.equal(gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]), 10);
|
||||
|
||||
(function testAutorestore() {
|
||||
assert.equal(OBJ2.foo(), 'bar');
|
||||
|
||||
gently.expect(OBJ2, 'foo', function() {
|
||||
return 'stubbed foo';
|
||||
});
|
||||
|
||||
gently.expect(OBJ2, 'foo', function() {
|
||||
return "didn't restore yet";
|
||||
});
|
||||
|
||||
assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), 'stubbed foo');
|
||||
assert.equal(gently._stubFn(SELF, OBJ2, 'foo', 'dummy_name', []), "didn't restore yet");
|
||||
assert.equal(OBJ2.foo(), 'bar');
|
||||
assert.deepEqual(gently.expectations, []);
|
||||
})();
|
||||
|
||||
(function testNoMoreCallExpected() {
|
||||
try {
|
||||
gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Unexpected call to dummy_name, no call was expected');
|
||||
}
|
||||
})();
|
||||
|
||||
(function testDifferentCallExpected() {
|
||||
gently.expect(OBJ2, 'bar');
|
||||
try {
|
||||
gently._stubFn(SELF, OBJ1, 'foo', 'dummy_name', [5]);
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Unexpected call to dummy_name, expected call to '+gently._name(OBJ2, 'bar'));
|
||||
}
|
||||
|
||||
assert.equal(gently.expectations.length, 1);
|
||||
})();
|
||||
|
||||
(function testNoMockCallback() {
|
||||
OBJ2.bar();
|
||||
assert.equal(gently.expectations.length, 0);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function stub() {
|
||||
var LOCATION = './my_class';
|
||||
|
||||
(function testRegular() {
|
||||
var Stub = gently.stub(LOCATION);
|
||||
assert.ok(Stub instanceof Function);
|
||||
assert.strictEqual(gently.hijacked[LOCATION], Stub);
|
||||
assert.ok(Stub['new'] instanceof Function);
|
||||
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
|
||||
|
||||
(function testConstructor() {
|
||||
var newCalled = 0
|
||||
, STUB
|
||||
, ARGS = ['foo', 'bar'];
|
||||
|
||||
Stub['new'] = function(a, b) {
|
||||
assert.equal(a, ARGS[0]);
|
||||
assert.equal(b, ARGS[1]);
|
||||
newCalled++;
|
||||
STUB = this;
|
||||
};
|
||||
|
||||
var stub = new Stub(ARGS[0], ARGS[1]);
|
||||
assert.strictEqual(stub, STUB);
|
||||
assert.equal(newCalled, 1);
|
||||
assert.equal(stub.toString(), 'require('+JSON.stringify(LOCATION)+')');
|
||||
})();
|
||||
|
||||
(function testUseReturnValueAsInstance() {
|
||||
var R = {};
|
||||
|
||||
Stub['new'] = function() {
|
||||
return R;
|
||||
};
|
||||
|
||||
var stub = new Stub();
|
||||
assert.strictEqual(stub, R);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
var EXPORTS_NAME = 'MyClass';
|
||||
test(function testExportsName() {
|
||||
var Stub = gently.stub(LOCATION, EXPORTS_NAME);
|
||||
assert.strictEqual(gently.hijacked[LOCATION][EXPORTS_NAME], Stub);
|
||||
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
|
||||
|
||||
(function testConstructor() {
|
||||
var stub = new Stub();
|
||||
assert.equal(Stub.toString(), 'require('+JSON.stringify(LOCATION)+').'+EXPORTS_NAME);
|
||||
})();
|
||||
});
|
||||
});
|
||||
|
||||
test(function hijack() {
|
||||
var LOCATION = './foo'
|
||||
, REQUIRE_CALLS = 0
|
||||
, EXPORTS = {}
|
||||
, REQUIRE = function() {
|
||||
REQUIRE_CALLS++;
|
||||
return EXPORTS;
|
||||
};
|
||||
|
||||
var hijackedRequire = gently.hijack(REQUIRE);
|
||||
hijackedRequire(LOCATION);
|
||||
assert.strictEqual(gently.hijacked[LOCATION], EXPORTS);
|
||||
|
||||
assert.equal(REQUIRE_CALLS, 1);
|
||||
|
||||
// make sure we are caching the hijacked module
|
||||
hijackedRequire(LOCATION);
|
||||
assert.equal(REQUIRE_CALLS, 1);
|
||||
});
|
||||
|
||||
test(function verify() {
|
||||
var OBJ = {toString: function() {return '[OBJ]'}};
|
||||
gently.verify();
|
||||
|
||||
gently.expect(OBJ, 'foo');
|
||||
try {
|
||||
gently.verify();
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen');
|
||||
}
|
||||
|
||||
try {
|
||||
gently.verify('foo');
|
||||
assert.ok(false, 'throw needs to happen');
|
||||
} catch (e) {
|
||||
assert.equal(e.message, 'Expected call to [OBJ].foo() did not happen (foo)');
|
||||
}
|
||||
});
|
||||
|
||||
test(function processExit() {
|
||||
var verifyCalled = 0;
|
||||
gently.verify = function(msg) {
|
||||
verifyCalled++;
|
||||
assert.equal(msg, 'process exit');
|
||||
};
|
||||
|
||||
process.emit('exit');
|
||||
assert.equal(verifyCalled, 1);
|
||||
});
|
||||
|
||||
test(function _name() {
|
||||
(function testNamedClass() {
|
||||
function Foo() {};
|
||||
var foo = new Foo();
|
||||
assert.equal(gently._name(foo, 'bar'), '[Foo].bar()');
|
||||
})();
|
||||
|
||||
(function testToStringPreference() {
|
||||
function Foo() {};
|
||||
Foo.prototype.toString = function() {
|
||||
return '[Superman 123]';
|
||||
};
|
||||
var foo = new Foo();
|
||||
assert.equal(gently._name(foo, 'bar'), '[Superman 123].bar()');
|
||||
})();
|
||||
|
||||
(function testUnamedClass() {
|
||||
var Foo = function() {};
|
||||
var foo = new Foo();
|
||||
assert.equal(gently._name(foo, 'bar'), foo.toString()+'.bar()');
|
||||
})();
|
||||
|
||||
(function testNamedClosure() {
|
||||
function myClosure() {};
|
||||
assert.equal(gently._name(null, null, myClosure), myClosure.name+'()');
|
||||
})();
|
||||
|
||||
(function testUnamedClosure() {
|
||||
var myClosure = function() {2+2 == 5};
|
||||
assert.equal(gently._name(null, null, myClosure), '>> '+myClosure.toString()+' <<');
|
||||
})();
|
||||
});
|
||||
|
||||
test(function verifyExpectNone() {
|
||||
var OBJ = {toString: function() {return '[OBJ]'}};
|
||||
gently.verify();
|
||||
|
||||
gently.expect(OBJ, 'foo', 0);
|
||||
try {
|
||||
gently.verify();
|
||||
} catch (e) {
|
||||
assert.fail('Exception should not have been thrown');
|
||||
}
|
||||
});
|
||||
29
app/node_modules/formidable/package.json
generated
vendored
Normal file
29
app/node_modules/formidable/package.json
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "formidable",
|
||||
"version": "1.0.11",
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"gently": "0.8.0",
|
||||
"findit": "0.1.1",
|
||||
"hashish": "0.0.4",
|
||||
"urun": "0.0.4",
|
||||
"utest": "0.0.3"
|
||||
},
|
||||
"directories": {
|
||||
"lib": "./lib"
|
||||
},
|
||||
"main": "./lib/index",
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"optionalDependencies": {},
|
||||
"_id": "formidable@1.0.11",
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "1.1.21",
|
||||
"_nodeVersion": "v0.6.18",
|
||||
"_defaultsLoaded": true,
|
||||
"_from": "formidable"
|
||||
}
|
||||
19
app/node_modules/formidable/test/common.js
generated
vendored
Normal file
19
app/node_modules/formidable/test/common.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
var mysql = require('..');
|
||||
var path = require('path');
|
||||
|
||||
var root = path.join(__dirname, '../');
|
||||
exports.dir = {
|
||||
root : root,
|
||||
lib : root + '/lib',
|
||||
fixture : root + '/test/fixture',
|
||||
tmp : root + '/test/tmp',
|
||||
};
|
||||
|
||||
exports.port = 13532;
|
||||
|
||||
exports.formidable = require('..');
|
||||
exports.assert = require('assert');
|
||||
|
||||
exports.require = function(lib) {
|
||||
return require(exports.dir.lib + '/' + lib);
|
||||
};
|
||||
1
app/node_modules/formidable/test/fixture/file/funkyfilename.txt
generated
vendored
Normal file
1
app/node_modules/formidable/test/fixture/file/funkyfilename.txt
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
I am a text file with a funky name!
|
||||
1
app/node_modules/formidable/test/fixture/file/plain.txt
generated
vendored
Normal file
1
app/node_modules/formidable/test/fixture/file/plain.txt
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
I am a plain text file
|
||||
3
app/node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md
generated
vendored
Normal file
3
app/node_modules/formidable/test/fixture/http/special-chars-in-filename/info.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* Opera does not allow submitting this file, it shows a warning to the
|
||||
user that the file could not be found instead. Tested in 9.8, 11.51 on OSX.
|
||||
Reported to Opera on 08.09.2011 (tracking email DSK-346009@bugs.opera.com).
|
||||
3
app/node_modules/formidable/test/fixture/js/no-filename.js
generated
vendored
Normal file
3
app/node_modules/formidable/test/fixture/js/no-filename.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports['generic.http'] = [
|
||||
{type: 'file', name: 'upload', filename: '', fixture: 'plain.txt'},
|
||||
];
|
||||
21
app/node_modules/formidable/test/fixture/js/special-chars-in-filename.js
generated
vendored
Normal file
21
app/node_modules/formidable/test/fixture/js/special-chars-in-filename.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
var properFilename = 'funkyfilename.txt';
|
||||
|
||||
function expect(filename) {
|
||||
return [
|
||||
{type: 'field', name: 'title', value: 'Weird filename'},
|
||||
{type: 'file', name: 'upload', filename: filename, fixture: properFilename},
|
||||
];
|
||||
};
|
||||
|
||||
var webkit = " ? % * | \" < > . ? ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
|
||||
var ffOrIe = " ? % * | \" < > . ☃ ; ' @ # $ ^ & ( ) - _ = + { } [ ] ` ~.txt";
|
||||
|
||||
module.exports = {
|
||||
'osx-chrome-13.http' : expect(webkit),
|
||||
'osx-firefox-3.6.http' : expect(ffOrIe),
|
||||
'osx-safari-5.http' : expect(webkit),
|
||||
'xp-chrome-12.http' : expect(webkit),
|
||||
'xp-ie-7.http' : expect(ffOrIe),
|
||||
'xp-ie-8.http' : expect(ffOrIe),
|
||||
'xp-safari-5.http' : expect(webkit),
|
||||
};
|
||||
72
app/node_modules/formidable/test/fixture/multipart.js
generated
vendored
Normal file
72
app/node_modules/formidable/test/fixture/multipart.js
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
exports['rfc1867'] =
|
||||
{ boundary: 'AaB03x',
|
||||
raw:
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="field1"\r\n'+
|
||||
'\r\n'+
|
||||
'Joe Blow\r\nalmost tricked you!\r\n'+
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
|
||||
'Content-Type: text/plain\r\n'+
|
||||
'\r\n'+
|
||||
'... contents of file1.txt ...\r\r\n'+
|
||||
'--AaB03x--\r\n',
|
||||
parts:
|
||||
[ { headers: {
|
||||
'content-disposition': 'form-data; name="field1"',
|
||||
},
|
||||
data: 'Joe Blow\r\nalmost tricked you!',
|
||||
},
|
||||
{ headers: {
|
||||
'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
data: '... contents of file1.txt ...\r',
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
exports['noTrailing\r\n'] =
|
||||
{ boundary: 'AaB03x',
|
||||
raw:
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="field1"\r\n'+
|
||||
'\r\n'+
|
||||
'Joe Blow\r\nalmost tricked you!\r\n'+
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
|
||||
'Content-Type: text/plain\r\n'+
|
||||
'\r\n'+
|
||||
'... contents of file1.txt ...\r\r\n'+
|
||||
'--AaB03x--',
|
||||
parts:
|
||||
[ { headers: {
|
||||
'content-disposition': 'form-data; name="field1"',
|
||||
},
|
||||
data: 'Joe Blow\r\nalmost tricked you!',
|
||||
},
|
||||
{ headers: {
|
||||
'content-disposition': 'form-data; name="pics"; filename="file1.txt"',
|
||||
'Content-Type': 'text/plain',
|
||||
},
|
||||
data: '... contents of file1.txt ...\r',
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
exports['emptyHeader'] =
|
||||
{ boundary: 'AaB03x',
|
||||
raw:
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="field1"\r\n'+
|
||||
': foo\r\n'+
|
||||
'\r\n'+
|
||||
'Joe Blow\r\nalmost tricked you!\r\n'+
|
||||
'--AaB03x\r\n'+
|
||||
'content-disposition: form-data; name="pics"; filename="file1.txt"\r\n'+
|
||||
'Content-Type: text/plain\r\n'+
|
||||
'\r\n'+
|
||||
'... contents of file1.txt ...\r\r\n'+
|
||||
'--AaB03x--\r\n',
|
||||
expectError: true,
|
||||
};
|
||||
89
app/node_modules/formidable/test/integration/test-fixtures.js
generated
vendored
Normal file
89
app/node_modules/formidable/test/integration/test-fixtures.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
var hashish = require('hashish');
|
||||
var fs = require('fs');
|
||||
var findit = require('findit');
|
||||
var path = require('path');
|
||||
var http = require('http');
|
||||
var net = require('net');
|
||||
var assert = require('assert');
|
||||
|
||||
var common = require('../common');
|
||||
var formidable = common.formidable;
|
||||
|
||||
var server = http.createServer();
|
||||
server.listen(common.port, findFixtures);
|
||||
|
||||
function findFixtures() {
|
||||
var fixtures = [];
|
||||
findit
|
||||
.sync(common.dir.fixture + '/js')
|
||||
.forEach(function(jsPath) {
|
||||
if (!/\.js$/.test(jsPath)) return;
|
||||
|
||||
var group = path.basename(jsPath, '.js');
|
||||
hashish.forEach(require(jsPath), function(fixture, name) {
|
||||
fixtures.push({
|
||||
name : group + '/' + name,
|
||||
fixture : fixture,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
testNext(fixtures);
|
||||
}
|
||||
|
||||
function testNext(fixtures) {
|
||||
var fixture = fixtures.shift();
|
||||
if (!fixture) return server.close();
|
||||
|
||||
var name = fixture.name;
|
||||
var fixture = fixture.fixture;
|
||||
|
||||
uploadFixture(name, function(err, parts) {
|
||||
if (err) throw err;
|
||||
|
||||
fixture.forEach(function(expectedPart, i) {
|
||||
var parsedPart = parts[i];
|
||||
assert.equal(parsedPart.type, expectedPart.type);
|
||||
assert.equal(parsedPart.name, expectedPart.name);
|
||||
|
||||
if (parsedPart.type === 'file') {
|
||||
var filename = parsedPart.value.name;
|
||||
assert.equal(filename, expectedPart.filename);
|
||||
}
|
||||
});
|
||||
|
||||
testNext(fixtures);
|
||||
});
|
||||
};
|
||||
|
||||
function uploadFixture(name, cb) {
|
||||
server.once('request', function(req, res) {
|
||||
var form = new formidable.IncomingForm();
|
||||
form.uploadDir = common.dir.tmp;
|
||||
form.parse(req);
|
||||
|
||||
function callback() {
|
||||
var realCallback = cb;
|
||||
cb = function() {};
|
||||
realCallback.apply(null, arguments);
|
||||
}
|
||||
|
||||
var parts = [];
|
||||
form
|
||||
.on('error', callback)
|
||||
.on('fileBegin', function(name, value) {
|
||||
parts.push({type: 'file', name: name, value: value});
|
||||
})
|
||||
.on('field', function(name, value) {
|
||||
parts.push({type: 'field', name: name, value: value});
|
||||
})
|
||||
.on('end', function() {
|
||||
callback(null, parts);
|
||||
});
|
||||
});
|
||||
|
||||
var socket = net.createConnection(common.port);
|
||||
var file = fs.createReadStream(common.dir.fixture + '/http/' + name);
|
||||
|
||||
file.pipe(socket);
|
||||
}
|
||||
24
app/node_modules/formidable/test/legacy/common.js
generated
vendored
Normal file
24
app/node_modules/formidable/test/legacy/common.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var path = require('path'),
|
||||
fs = require('fs');
|
||||
|
||||
try {
|
||||
global.Gently = require('gently');
|
||||
} catch (e) {
|
||||
throw new Error('this test suite requires node-gently');
|
||||
}
|
||||
|
||||
exports.lib = path.join(__dirname, '../../lib');
|
||||
|
||||
global.GENTLY = new Gently();
|
||||
|
||||
global.assert = require('assert');
|
||||
global.TEST_PORT = 13532;
|
||||
global.TEST_FIXTURES = path.join(__dirname, '../fixture');
|
||||
global.TEST_TMP = path.join(__dirname, '../tmp');
|
||||
|
||||
// Stupid new feature in node that complains about gently attaching too many
|
||||
// listeners to process 'exit'. This is a workaround until I can think of a
|
||||
// better way to deal with this.
|
||||
if (process.setMaxListeners) {
|
||||
process.setMaxListeners(10000);
|
||||
}
|
||||
80
app/node_modules/formidable/test/legacy/integration/test-multipart-parser.js
generated
vendored
Normal file
80
app/node_modules/formidable/test/legacy/integration/test-multipart-parser.js
generated
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
var common = require('../common');
|
||||
var CHUNK_LENGTH = 10,
|
||||
multipartParser = require(common.lib + '/multipart_parser'),
|
||||
MultipartParser = multipartParser.MultipartParser,
|
||||
parser = new MultipartParser(),
|
||||
fixtures = require(TEST_FIXTURES + '/multipart'),
|
||||
Buffer = require('buffer').Buffer;
|
||||
|
||||
Object.keys(fixtures).forEach(function(name) {
|
||||
var fixture = fixtures[name],
|
||||
buffer = new Buffer(Buffer.byteLength(fixture.raw, 'binary')),
|
||||
offset = 0,
|
||||
chunk,
|
||||
nparsed,
|
||||
|
||||
parts = [],
|
||||
part = null,
|
||||
headerField,
|
||||
headerValue,
|
||||
endCalled = '';
|
||||
|
||||
parser.initWithBoundary(fixture.boundary);
|
||||
parser.onPartBegin = function() {
|
||||
part = {headers: {}, data: ''};
|
||||
parts.push(part);
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
};
|
||||
|
||||
parser.onHeaderField = function(b, start, end) {
|
||||
headerField += b.toString('ascii', start, end);
|
||||
};
|
||||
|
||||
parser.onHeaderValue = function(b, start, end) {
|
||||
headerValue += b.toString('ascii', start, end);
|
||||
}
|
||||
|
||||
parser.onHeaderEnd = function() {
|
||||
part.headers[headerField] = headerValue;
|
||||
headerField = '';
|
||||
headerValue = '';
|
||||
};
|
||||
|
||||
parser.onPartData = function(b, start, end) {
|
||||
var str = b.toString('ascii', start, end);
|
||||
part.data += b.slice(start, end);
|
||||
}
|
||||
|
||||
parser.onEnd = function() {
|
||||
endCalled = true;
|
||||
}
|
||||
|
||||
buffer.write(fixture.raw, 'binary', 0);
|
||||
|
||||
while (offset < buffer.length) {
|
||||
if (offset + CHUNK_LENGTH < buffer.length) {
|
||||
chunk = buffer.slice(offset, offset+CHUNK_LENGTH);
|
||||
} else {
|
||||
chunk = buffer.slice(offset, buffer.length);
|
||||
}
|
||||
offset = offset + CHUNK_LENGTH;
|
||||
|
||||
nparsed = parser.write(chunk);
|
||||
if (nparsed != chunk.length) {
|
||||
if (fixture.expectError) {
|
||||
return;
|
||||
}
|
||||
puts('-- ERROR --');
|
||||
p(chunk.toString('ascii'));
|
||||
throw new Error(chunk.length+' bytes written, but only '+nparsed+' bytes parsed!');
|
||||
}
|
||||
}
|
||||
|
||||
if (fixture.expectError) {
|
||||
throw new Error('expected parse error did not happen');
|
||||
}
|
||||
|
||||
assert.ok(endCalled);
|
||||
assert.deepEqual(parts, fixture.parts);
|
||||
});
|
||||
104
app/node_modules/formidable/test/legacy/simple/test-file.js
generated
vendored
Normal file
104
app/node_modules/formidable/test/legacy/simple/test-file.js
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
var common = require('../common');
|
||||
var WriteStreamStub = GENTLY.stub('fs', 'WriteStream');
|
||||
|
||||
var File = require(common.lib + '/file'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
file,
|
||||
gently;
|
||||
|
||||
function test(test) {
|
||||
gently = new Gently();
|
||||
file = new File();
|
||||
test();
|
||||
gently.verify(test.name);
|
||||
}
|
||||
|
||||
test(function constructor() {
|
||||
assert.ok(file instanceof EventEmitter);
|
||||
assert.strictEqual(file.size, 0);
|
||||
assert.strictEqual(file.path, null);
|
||||
assert.strictEqual(file.name, null);
|
||||
assert.strictEqual(file.type, null);
|
||||
assert.strictEqual(file.lastModifiedDate, null);
|
||||
|
||||
assert.strictEqual(file._writeStream, null);
|
||||
|
||||
(function testSetProperties() {
|
||||
var file2 = new File({foo: 'bar'});
|
||||
assert.equal(file2.foo, 'bar');
|
||||
})();
|
||||
});
|
||||
|
||||
test(function open() {
|
||||
var WRITE_STREAM;
|
||||
file.path = '/foo';
|
||||
|
||||
gently.expect(WriteStreamStub, 'new', function (path) {
|
||||
WRITE_STREAM = this;
|
||||
assert.strictEqual(path, file.path);
|
||||
});
|
||||
|
||||
file.open();
|
||||
assert.strictEqual(file._writeStream, WRITE_STREAM);
|
||||
});
|
||||
|
||||
test(function write() {
|
||||
var BUFFER = {length: 10},
|
||||
CB_STUB,
|
||||
CB = function() {
|
||||
CB_STUB.apply(this, arguments);
|
||||
};
|
||||
|
||||
file._writeStream = {};
|
||||
|
||||
gently.expect(file._writeStream, 'write', function (buffer, cb) {
|
||||
assert.strictEqual(buffer, BUFFER);
|
||||
|
||||
gently.expect(file, 'emit', function (event, bytesWritten) {
|
||||
assert.ok(file.lastModifiedDate instanceof Date);
|
||||
assert.equal(event, 'progress');
|
||||
assert.equal(bytesWritten, file.size);
|
||||
});
|
||||
|
||||
CB_STUB = gently.expect(function writeCb() {
|
||||
assert.equal(file.size, 10);
|
||||
});
|
||||
|
||||
cb();
|
||||
|
||||
gently.expect(file, 'emit', function (event, bytesWritten) {
|
||||
assert.equal(event, 'progress');
|
||||
assert.equal(bytesWritten, file.size);
|
||||
});
|
||||
|
||||
CB_STUB = gently.expect(function writeCb() {
|
||||
assert.equal(file.size, 20);
|
||||
});
|
||||
|
||||
cb();
|
||||
});
|
||||
|
||||
file.write(BUFFER, CB);
|
||||
});
|
||||
|
||||
test(function end() {
|
||||
var CB_STUB,
|
||||
CB = function() {
|
||||
CB_STUB.apply(this, arguments);
|
||||
};
|
||||
|
||||
file._writeStream = {};
|
||||
|
||||
gently.expect(file._writeStream, 'end', function (cb) {
|
||||
gently.expect(file, 'emit', function (event) {
|
||||
assert.equal(event, 'end');
|
||||
});
|
||||
|
||||
CB_STUB = gently.expect(function endCb() {
|
||||
});
|
||||
|
||||
cb();
|
||||
});
|
||||
|
||||
file.end(CB);
|
||||
});
|
||||
727
app/node_modules/formidable/test/legacy/simple/test-incoming-form.js
generated
vendored
Normal file
727
app/node_modules/formidable/test/legacy/simple/test-incoming-form.js
generated
vendored
Normal file
@@ -0,0 +1,727 @@
|
||||
var common = require('../common');
|
||||
var MultipartParserStub = GENTLY.stub('./multipart_parser', 'MultipartParser'),
|
||||
QuerystringParserStub = GENTLY.stub('./querystring_parser', 'QuerystringParser'),
|
||||
EventEmitterStub = GENTLY.stub('events', 'EventEmitter'),
|
||||
StreamStub = GENTLY.stub('stream', 'Stream'),
|
||||
FileStub = GENTLY.stub('./file');
|
||||
|
||||
var formidable = require(common.lib + '/index'),
|
||||
IncomingForm = formidable.IncomingForm,
|
||||
events = require('events'),
|
||||
fs = require('fs'),
|
||||
path = require('path'),
|
||||
Buffer = require('buffer').Buffer,
|
||||
fixtures = require(TEST_FIXTURES + '/multipart'),
|
||||
form,
|
||||
gently;
|
||||
|
||||
function test(test) {
|
||||
gently = new Gently();
|
||||
gently.expect(EventEmitterStub, 'call');
|
||||
form = new IncomingForm();
|
||||
test();
|
||||
gently.verify(test.name);
|
||||
}
|
||||
|
||||
test(function constructor() {
|
||||
assert.strictEqual(form.error, null);
|
||||
assert.strictEqual(form.ended, false);
|
||||
assert.strictEqual(form.type, null);
|
||||
assert.strictEqual(form.headers, null);
|
||||
assert.strictEqual(form.keepExtensions, false);
|
||||
assert.strictEqual(form.uploadDir, '/tmp');
|
||||
assert.strictEqual(form.encoding, 'utf-8');
|
||||
assert.strictEqual(form.bytesReceived, null);
|
||||
assert.strictEqual(form.bytesExpected, null);
|
||||
assert.strictEqual(form.maxFieldsSize, 2 * 1024 * 1024);
|
||||
assert.strictEqual(form._parser, null);
|
||||
assert.strictEqual(form._flushing, 0);
|
||||
assert.strictEqual(form._fieldsSize, 0);
|
||||
assert.ok(form instanceof EventEmitterStub);
|
||||
assert.equal(form.constructor.name, 'IncomingForm');
|
||||
|
||||
(function testSimpleConstructor() {
|
||||
gently.expect(EventEmitterStub, 'call');
|
||||
var form = IncomingForm();
|
||||
assert.ok(form instanceof IncomingForm);
|
||||
})();
|
||||
|
||||
(function testSimpleConstructorShortcut() {
|
||||
gently.expect(EventEmitterStub, 'call');
|
||||
var form = formidable();
|
||||
assert.ok(form instanceof IncomingForm);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function parse() {
|
||||
var REQ = {headers: {}}
|
||||
, emit = {};
|
||||
|
||||
gently.expect(form, 'writeHeaders', function(headers) {
|
||||
assert.strictEqual(headers, REQ.headers);
|
||||
});
|
||||
|
||||
var events = ['error', 'aborted', 'data', 'end'];
|
||||
gently.expect(REQ, 'on', events.length, function(event, fn) {
|
||||
assert.equal(event, events.shift());
|
||||
emit[event] = fn;
|
||||
return this;
|
||||
});
|
||||
|
||||
form.parse(REQ);
|
||||
|
||||
(function testPause() {
|
||||
gently.expect(REQ, 'pause');
|
||||
assert.strictEqual(form.pause(), true);
|
||||
})();
|
||||
|
||||
(function testPauseCriticalException() {
|
||||
form.ended = false;
|
||||
|
||||
var ERR = new Error('dasdsa');
|
||||
gently.expect(REQ, 'pause', function() {
|
||||
throw ERR;
|
||||
});
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.strictEqual(err, ERR);
|
||||
});
|
||||
|
||||
assert.strictEqual(form.pause(), false);
|
||||
})();
|
||||
|
||||
(function testPauseHarmlessException() {
|
||||
form.ended = true;
|
||||
|
||||
var ERR = new Error('dasdsa');
|
||||
gently.expect(REQ, 'pause', function() {
|
||||
throw ERR;
|
||||
});
|
||||
|
||||
assert.strictEqual(form.pause(), false);
|
||||
})();
|
||||
|
||||
(function testResume() {
|
||||
gently.expect(REQ, 'resume');
|
||||
assert.strictEqual(form.resume(), true);
|
||||
})();
|
||||
|
||||
(function testResumeCriticalException() {
|
||||
form.ended = false;
|
||||
|
||||
var ERR = new Error('dasdsa');
|
||||
gently.expect(REQ, 'resume', function() {
|
||||
throw ERR;
|
||||
});
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.strictEqual(err, ERR);
|
||||
});
|
||||
|
||||
assert.strictEqual(form.resume(), false);
|
||||
})();
|
||||
|
||||
(function testResumeHarmlessException() {
|
||||
form.ended = true;
|
||||
|
||||
var ERR = new Error('dasdsa');
|
||||
gently.expect(REQ, 'resume', function() {
|
||||
throw ERR;
|
||||
});
|
||||
|
||||
assert.strictEqual(form.resume(), false);
|
||||
})();
|
||||
|
||||
(function testEmitError() {
|
||||
var ERR = new Error('something bad happened');
|
||||
gently.expect(form, '_error',function(err) {
|
||||
assert.strictEqual(err, ERR);
|
||||
});
|
||||
emit.error(ERR);
|
||||
})();
|
||||
|
||||
(function testEmitAborted() {
|
||||
gently.expect(form, 'emit',function(event) {
|
||||
assert.equal(event, 'aborted');
|
||||
});
|
||||
|
||||
emit.aborted();
|
||||
})();
|
||||
|
||||
|
||||
(function testEmitData() {
|
||||
var BUFFER = [1, 2, 3];
|
||||
gently.expect(form, 'write', function(buffer) {
|
||||
assert.strictEqual(buffer, BUFFER);
|
||||
});
|
||||
emit.data(BUFFER);
|
||||
})();
|
||||
|
||||
(function testEmitEnd() {
|
||||
form._parser = {};
|
||||
|
||||
(function testWithError() {
|
||||
var ERR = new Error('haha');
|
||||
gently.expect(form._parser, 'end', function() {
|
||||
return ERR;
|
||||
});
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.strictEqual(err, ERR);
|
||||
});
|
||||
|
||||
emit.end();
|
||||
})();
|
||||
|
||||
(function testWithoutError() {
|
||||
gently.expect(form._parser, 'end');
|
||||
emit.end();
|
||||
})();
|
||||
|
||||
(function testAfterError() {
|
||||
form.error = true;
|
||||
emit.end();
|
||||
})();
|
||||
})();
|
||||
|
||||
(function testWithCallback() {
|
||||
gently.expect(EventEmitterStub, 'call');
|
||||
var form = new IncomingForm(),
|
||||
REQ = {headers: {}},
|
||||
parseCalled = 0;
|
||||
|
||||
gently.expect(form, 'writeHeaders');
|
||||
gently.expect(REQ, 'on', 4, function() {
|
||||
return this;
|
||||
});
|
||||
|
||||
gently.expect(form, 'on', 4, function(event, fn) {
|
||||
if (event == 'field') {
|
||||
fn('field1', 'foo');
|
||||
fn('field1', 'bar');
|
||||
fn('field2', 'nice');
|
||||
}
|
||||
|
||||
if (event == 'file') {
|
||||
fn('file1', '1');
|
||||
fn('file1', '2');
|
||||
fn('file2', '3');
|
||||
}
|
||||
|
||||
if (event == 'end') {
|
||||
fn();
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
form.parse(REQ, gently.expect(function parseCbOk(err, fields, files) {
|
||||
assert.deepEqual(fields, {field1: 'bar', field2: 'nice'});
|
||||
assert.deepEqual(files, {file1: '2', file2: '3'});
|
||||
}));
|
||||
|
||||
gently.expect(form, 'writeHeaders');
|
||||
gently.expect(REQ, 'on', 4, function() {
|
||||
return this;
|
||||
});
|
||||
|
||||
var ERR = new Error('test');
|
||||
gently.expect(form, 'on', 3, function(event, fn) {
|
||||
if (event == 'field') {
|
||||
fn('foo', 'bar');
|
||||
}
|
||||
|
||||
if (event == 'error') {
|
||||
fn(ERR);
|
||||
gently.expect(form, 'on');
|
||||
}
|
||||
return this;
|
||||
});
|
||||
|
||||
form.parse(REQ, gently.expect(function parseCbErr(err, fields, files) {
|
||||
assert.strictEqual(err, ERR);
|
||||
assert.deepEqual(fields, {foo: 'bar'});
|
||||
}));
|
||||
})();
|
||||
});
|
||||
|
||||
test(function pause() {
|
||||
assert.strictEqual(form.pause(), false);
|
||||
});
|
||||
|
||||
test(function resume() {
|
||||
assert.strictEqual(form.resume(), false);
|
||||
});
|
||||
|
||||
|
||||
test(function writeHeaders() {
|
||||
var HEADERS = {};
|
||||
gently.expect(form, '_parseContentLength');
|
||||
gently.expect(form, '_parseContentType');
|
||||
|
||||
form.writeHeaders(HEADERS);
|
||||
assert.strictEqual(form.headers, HEADERS);
|
||||
});
|
||||
|
||||
test(function write() {
|
||||
var parser = {},
|
||||
BUFFER = [1, 2, 3];
|
||||
|
||||
form._parser = parser;
|
||||
form.bytesExpected = 523423;
|
||||
|
||||
(function testBasic() {
|
||||
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
|
||||
assert.equal(event, 'progress');
|
||||
assert.equal(bytesReceived, BUFFER.length);
|
||||
assert.equal(bytesExpected, form.bytesExpected);
|
||||
});
|
||||
|
||||
gently.expect(parser, 'write', function(buffer) {
|
||||
assert.strictEqual(buffer, BUFFER);
|
||||
return buffer.length;
|
||||
});
|
||||
|
||||
assert.equal(form.write(BUFFER), BUFFER.length);
|
||||
assert.equal(form.bytesReceived, BUFFER.length);
|
||||
})();
|
||||
|
||||
(function testParserError() {
|
||||
gently.expect(form, 'emit');
|
||||
|
||||
gently.expect(parser, 'write', function(buffer) {
|
||||
assert.strictEqual(buffer, BUFFER);
|
||||
return buffer.length - 1;
|
||||
});
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.ok(err.message.match(/parser error/i));
|
||||
});
|
||||
|
||||
assert.equal(form.write(BUFFER), BUFFER.length - 1);
|
||||
assert.equal(form.bytesReceived, BUFFER.length + BUFFER.length);
|
||||
})();
|
||||
|
||||
(function testUninitialized() {
|
||||
delete form._parser;
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.ok(err.message.match(/unintialized parser/i));
|
||||
});
|
||||
form.write(BUFFER);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function parseContentType() {
|
||||
var HEADERS = {};
|
||||
|
||||
form.headers = {'content-type': 'application/x-www-form-urlencoded'};
|
||||
gently.expect(form, '_initUrlencoded');
|
||||
form._parseContentType();
|
||||
|
||||
// accept anything that has 'urlencoded' in it
|
||||
form.headers = {'content-type': 'broken-client/urlencoded-stupid'};
|
||||
gently.expect(form, '_initUrlencoded');
|
||||
form._parseContentType();
|
||||
|
||||
var BOUNDARY = '---------------------------57814261102167618332366269';
|
||||
form.headers = {'content-type': 'multipart/form-data; boundary='+BOUNDARY};
|
||||
|
||||
gently.expect(form, '_initMultipart', function(boundary) {
|
||||
assert.equal(boundary, BOUNDARY);
|
||||
});
|
||||
form._parseContentType();
|
||||
|
||||
(function testQuotedBoundary() {
|
||||
form.headers = {'content-type': 'multipart/form-data; boundary="' + BOUNDARY + '"'};
|
||||
|
||||
gently.expect(form, '_initMultipart', function(boundary) {
|
||||
assert.equal(boundary, BOUNDARY);
|
||||
});
|
||||
form._parseContentType();
|
||||
})();
|
||||
|
||||
(function testNoBoundary() {
|
||||
form.headers = {'content-type': 'multipart/form-data'};
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.ok(err.message.match(/no multipart boundary/i));
|
||||
});
|
||||
form._parseContentType();
|
||||
})();
|
||||
|
||||
(function testNoContentType() {
|
||||
form.headers = {};
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.ok(err.message.match(/no content-type/i));
|
||||
});
|
||||
form._parseContentType();
|
||||
})();
|
||||
|
||||
(function testUnknownContentType() {
|
||||
form.headers = {'content-type': 'invalid'};
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.ok(err.message.match(/unknown content-type/i));
|
||||
});
|
||||
form._parseContentType();
|
||||
})();
|
||||
});
|
||||
|
||||
test(function parseContentLength() {
|
||||
var HEADERS = {};
|
||||
|
||||
form.headers = {};
|
||||
form._parseContentLength();
|
||||
assert.strictEqual(form.bytesReceived, null);
|
||||
assert.strictEqual(form.bytesExpected, null);
|
||||
|
||||
form.headers['content-length'] = '8';
|
||||
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
|
||||
assert.equal(event, 'progress');
|
||||
assert.equal(bytesReceived, 0);
|
||||
assert.equal(bytesExpected, 8);
|
||||
});
|
||||
form._parseContentLength();
|
||||
assert.strictEqual(form.bytesReceived, 0);
|
||||
assert.strictEqual(form.bytesExpected, 8);
|
||||
|
||||
// JS can be evil, lets make sure we are not
|
||||
form.headers['content-length'] = '08';
|
||||
gently.expect(form, 'emit', function(event, bytesReceived, bytesExpected) {
|
||||
assert.equal(event, 'progress');
|
||||
assert.equal(bytesReceived, 0);
|
||||
assert.equal(bytesExpected, 8);
|
||||
});
|
||||
form._parseContentLength();
|
||||
assert.strictEqual(form.bytesExpected, 8);
|
||||
});
|
||||
|
||||
test(function _initMultipart() {
|
||||
var BOUNDARY = '123',
|
||||
PARSER;
|
||||
|
||||
gently.expect(MultipartParserStub, 'new', function() {
|
||||
PARSER = this;
|
||||
});
|
||||
|
||||
gently.expect(MultipartParserStub.prototype, 'initWithBoundary', function(boundary) {
|
||||
assert.equal(boundary, BOUNDARY);
|
||||
});
|
||||
|
||||
form._initMultipart(BOUNDARY);
|
||||
assert.equal(form.type, 'multipart');
|
||||
assert.strictEqual(form._parser, PARSER);
|
||||
|
||||
(function testRegularField() {
|
||||
var PART;
|
||||
gently.expect(StreamStub, 'new', function() {
|
||||
PART = this;
|
||||
});
|
||||
|
||||
gently.expect(form, 'onPart', function(part) {
|
||||
assert.strictEqual(part, PART);
|
||||
assert.deepEqual
|
||||
( part.headers
|
||||
, { 'content-disposition': 'form-data; name="field1"'
|
||||
, 'foo': 'bar'
|
||||
}
|
||||
);
|
||||
assert.equal(part.name, 'field1');
|
||||
|
||||
var strings = ['hello', ' world'];
|
||||
gently.expect(part, 'emit', 2, function(event, b) {
|
||||
assert.equal(event, 'data');
|
||||
assert.equal(b.toString(), strings.shift());
|
||||
});
|
||||
|
||||
gently.expect(part, 'emit', function(event, b) {
|
||||
assert.equal(event, 'end');
|
||||
});
|
||||
});
|
||||
|
||||
PARSER.onPartBegin();
|
||||
PARSER.onHeaderField(new Buffer('content-disposition'), 0, 10);
|
||||
PARSER.onHeaderField(new Buffer('content-disposition'), 10, 19);
|
||||
PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 0, 14);
|
||||
PARSER.onHeaderValue(new Buffer('form-data; name="field1"'), 14, 24);
|
||||
PARSER.onHeaderEnd();
|
||||
PARSER.onHeaderField(new Buffer('foo'), 0, 3);
|
||||
PARSER.onHeaderValue(new Buffer('bar'), 0, 3);
|
||||
PARSER.onHeaderEnd();
|
||||
PARSER.onHeadersEnd();
|
||||
PARSER.onPartData(new Buffer('hello world'), 0, 5);
|
||||
PARSER.onPartData(new Buffer('hello world'), 5, 11);
|
||||
PARSER.onPartEnd();
|
||||
})();
|
||||
|
||||
(function testFileField() {
|
||||
var PART;
|
||||
gently.expect(StreamStub, 'new', function() {
|
||||
PART = this;
|
||||
});
|
||||
|
||||
gently.expect(form, 'onPart', function(part) {
|
||||
assert.deepEqual
|
||||
( part.headers
|
||||
, { 'content-disposition': 'form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'
|
||||
, 'content-type': 'text/plain'
|
||||
}
|
||||
);
|
||||
assert.equal(part.name, 'field2');
|
||||
assert.equal(part.filename, 'Sun"et.jpg');
|
||||
assert.equal(part.mime, 'text/plain');
|
||||
|
||||
gently.expect(part, 'emit', function(event, b) {
|
||||
assert.equal(event, 'data');
|
||||
assert.equal(b.toString(), '... contents of file1.txt ...');
|
||||
});
|
||||
|
||||
gently.expect(part, 'emit', function(event, b) {
|
||||
assert.equal(event, 'end');
|
||||
});
|
||||
});
|
||||
|
||||
PARSER.onPartBegin();
|
||||
PARSER.onHeaderField(new Buffer('content-disposition'), 0, 19);
|
||||
PARSER.onHeaderValue(new Buffer('form-data; name="field2"; filename="C:\\Documents and Settings\\IE\\Must\\Die\\Sun"et.jpg"'), 0, 85);
|
||||
PARSER.onHeaderEnd();
|
||||
PARSER.onHeaderField(new Buffer('Content-Type'), 0, 12);
|
||||
PARSER.onHeaderValue(new Buffer('text/plain'), 0, 10);
|
||||
PARSER.onHeaderEnd();
|
||||
PARSER.onHeadersEnd();
|
||||
PARSER.onPartData(new Buffer('... contents of file1.txt ...'), 0, 29);
|
||||
PARSER.onPartEnd();
|
||||
})();
|
||||
|
||||
(function testEnd() {
|
||||
gently.expect(form, '_maybeEnd');
|
||||
PARSER.onEnd();
|
||||
assert.ok(form.ended);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function _fileName() {
|
||||
// TODO
|
||||
return;
|
||||
});
|
||||
|
||||
test(function _initUrlencoded() {
|
||||
var PARSER;
|
||||
|
||||
gently.expect(QuerystringParserStub, 'new', function() {
|
||||
PARSER = this;
|
||||
});
|
||||
|
||||
form._initUrlencoded();
|
||||
assert.equal(form.type, 'urlencoded');
|
||||
assert.strictEqual(form._parser, PARSER);
|
||||
|
||||
(function testOnField() {
|
||||
var KEY = 'KEY', VAL = 'VAL';
|
||||
gently.expect(form, 'emit', function(field, key, val) {
|
||||
assert.equal(field, 'field');
|
||||
assert.equal(key, KEY);
|
||||
assert.equal(val, VAL);
|
||||
});
|
||||
|
||||
PARSER.onField(KEY, VAL);
|
||||
})();
|
||||
|
||||
(function testOnEnd() {
|
||||
gently.expect(form, '_maybeEnd');
|
||||
|
||||
PARSER.onEnd();
|
||||
assert.equal(form.ended, true);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function _error() {
|
||||
var ERR = new Error('bla');
|
||||
|
||||
gently.expect(form, 'pause');
|
||||
gently.expect(form, 'emit', function(event, err) {
|
||||
assert.equal(event, 'error');
|
||||
assert.strictEqual(err, ERR);
|
||||
});
|
||||
|
||||
form._error(ERR);
|
||||
assert.strictEqual(form.error, ERR);
|
||||
|
||||
// make sure _error only does its thing once
|
||||
form._error(ERR);
|
||||
});
|
||||
|
||||
test(function onPart() {
|
||||
var PART = {};
|
||||
gently.expect(form, 'handlePart', function(part) {
|
||||
assert.strictEqual(part, PART);
|
||||
});
|
||||
|
||||
form.onPart(PART);
|
||||
});
|
||||
|
||||
test(function handlePart() {
|
||||
(function testUtf8Field() {
|
||||
var PART = new events.EventEmitter();
|
||||
PART.name = 'my_field';
|
||||
|
||||
gently.expect(form, 'emit', function(event, field, value) {
|
||||
assert.equal(event, 'field');
|
||||
assert.equal(field, 'my_field');
|
||||
assert.equal(value, 'hello world: €');
|
||||
});
|
||||
|
||||
form.handlePart(PART);
|
||||
PART.emit('data', new Buffer('hello'));
|
||||
PART.emit('data', new Buffer(' world: '));
|
||||
PART.emit('data', new Buffer([0xE2]));
|
||||
PART.emit('data', new Buffer([0x82, 0xAC]));
|
||||
PART.emit('end');
|
||||
})();
|
||||
|
||||
(function testBinaryField() {
|
||||
var PART = new events.EventEmitter();
|
||||
PART.name = 'my_field2';
|
||||
|
||||
gently.expect(form, 'emit', function(event, field, value) {
|
||||
assert.equal(event, 'field');
|
||||
assert.equal(field, 'my_field2');
|
||||
assert.equal(value, 'hello world: '+new Buffer([0xE2, 0x82, 0xAC]).toString('binary'));
|
||||
});
|
||||
|
||||
form.encoding = 'binary';
|
||||
form.handlePart(PART);
|
||||
PART.emit('data', new Buffer('hello'));
|
||||
PART.emit('data', new Buffer(' world: '));
|
||||
PART.emit('data', new Buffer([0xE2]));
|
||||
PART.emit('data', new Buffer([0x82, 0xAC]));
|
||||
PART.emit('end');
|
||||
})();
|
||||
|
||||
(function testFieldSize() {
|
||||
form.maxFieldsSize = 8;
|
||||
var PART = new events.EventEmitter();
|
||||
PART.name = 'my_field';
|
||||
|
||||
gently.expect(form, '_error', function(err) {
|
||||
assert.equal(err.message, 'maxFieldsSize exceeded, received 9 bytes of field data');
|
||||
});
|
||||
|
||||
form.handlePart(PART);
|
||||
form._fieldsSize = 1;
|
||||
PART.emit('data', new Buffer(7));
|
||||
PART.emit('data', new Buffer(1));
|
||||
})();
|
||||
|
||||
(function testFilePart() {
|
||||
var PART = new events.EventEmitter(),
|
||||
FILE = new events.EventEmitter(),
|
||||
PATH = '/foo/bar';
|
||||
|
||||
PART.name = 'my_file';
|
||||
PART.filename = 'sweet.txt';
|
||||
PART.mime = 'sweet.txt';
|
||||
|
||||
gently.expect(form, '_uploadPath', function(filename) {
|
||||
assert.equal(filename, PART.filename);
|
||||
return PATH;
|
||||
});
|
||||
|
||||
gently.expect(FileStub, 'new', function(properties) {
|
||||
assert.equal(properties.path, PATH);
|
||||
assert.equal(properties.name, PART.filename);
|
||||
assert.equal(properties.type, PART.mime);
|
||||
FILE = this;
|
||||
|
||||
gently.expect(form, 'emit', function (event, field, file) {
|
||||
assert.equal(event, 'fileBegin');
|
||||
assert.strictEqual(field, PART.name);
|
||||
assert.strictEqual(file, FILE);
|
||||
});
|
||||
|
||||
gently.expect(FILE, 'open');
|
||||
});
|
||||
|
||||
form.handlePart(PART);
|
||||
assert.equal(form._flushing, 1);
|
||||
|
||||
var BUFFER;
|
||||
gently.expect(form, 'pause');
|
||||
gently.expect(FILE, 'write', function(buffer, cb) {
|
||||
assert.strictEqual(buffer, BUFFER);
|
||||
gently.expect(form, 'resume');
|
||||
// @todo handle cb(new Err)
|
||||
cb();
|
||||
});
|
||||
|
||||
PART.emit('data', BUFFER = new Buffer('test'));
|
||||
|
||||
gently.expect(FILE, 'end', function(cb) {
|
||||
gently.expect(form, 'emit', function(event, field, file) {
|
||||
assert.equal(event, 'file');
|
||||
assert.strictEqual(file, FILE);
|
||||
});
|
||||
|
||||
gently.expect(form, '_maybeEnd');
|
||||
|
||||
cb();
|
||||
assert.equal(form._flushing, 0);
|
||||
});
|
||||
|
||||
PART.emit('end');
|
||||
})();
|
||||
});
|
||||
|
||||
test(function _uploadPath() {
|
||||
(function testUniqueId() {
|
||||
var UUID_A, UUID_B;
|
||||
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {
|
||||
assert.equal(uploadDir, form.uploadDir);
|
||||
UUID_A = uuid;
|
||||
});
|
||||
form._uploadPath();
|
||||
|
||||
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, uuid) {
|
||||
UUID_B = uuid;
|
||||
});
|
||||
form._uploadPath();
|
||||
|
||||
assert.notEqual(UUID_A, UUID_B);
|
||||
})();
|
||||
|
||||
(function testFileExtension() {
|
||||
form.keepExtensions = true;
|
||||
var FILENAME = 'foo.jpg',
|
||||
EXT = '.bar';
|
||||
|
||||
gently.expect(GENTLY.hijacked.path, 'extname', function(filename) {
|
||||
assert.equal(filename, FILENAME);
|
||||
gently.restore(path, 'extname');
|
||||
|
||||
return EXT;
|
||||
});
|
||||
|
||||
gently.expect(GENTLY.hijacked.path, 'join', function(uploadDir, name) {
|
||||
assert.equal(path.extname(name), EXT);
|
||||
});
|
||||
form._uploadPath(FILENAME);
|
||||
})();
|
||||
});
|
||||
|
||||
test(function _maybeEnd() {
|
||||
gently.expect(form, 'emit', 0);
|
||||
form._maybeEnd();
|
||||
|
||||
form.ended = true;
|
||||
form._flushing = 1;
|
||||
form._maybeEnd();
|
||||
|
||||
gently.expect(form, 'emit', function(event) {
|
||||
assert.equal(event, 'end');
|
||||
});
|
||||
|
||||
form.ended = true;
|
||||
form._flushing = 0;
|
||||
form._maybeEnd();
|
||||
});
|
||||
50
app/node_modules/formidable/test/legacy/simple/test-multipart-parser.js
generated
vendored
Normal file
50
app/node_modules/formidable/test/legacy/simple/test-multipart-parser.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
var common = require('../common');
|
||||
var multipartParser = require(common.lib + '/multipart_parser'),
|
||||
MultipartParser = multipartParser.MultipartParser,
|
||||
events = require('events'),
|
||||
Buffer = require('buffer').Buffer,
|
||||
parser;
|
||||
|
||||
function test(test) {
|
||||
parser = new MultipartParser();
|
||||
test();
|
||||
}
|
||||
|
||||
test(function constructor() {
|
||||
assert.equal(parser.boundary, null);
|
||||
assert.equal(parser.state, 0);
|
||||
assert.equal(parser.flags, 0);
|
||||
assert.equal(parser.boundaryChars, null);
|
||||
assert.equal(parser.index, null);
|
||||
assert.equal(parser.lookbehind, null);
|
||||
assert.equal(parser.constructor.name, 'MultipartParser');
|
||||
});
|
||||
|
||||
test(function initWithBoundary() {
|
||||
var boundary = 'abc';
|
||||
parser.initWithBoundary(boundary);
|
||||
assert.deepEqual(Array.prototype.slice.call(parser.boundary), [13, 10, 45, 45, 97, 98, 99]);
|
||||
assert.equal(parser.state, multipartParser.START);
|
||||
|
||||
assert.deepEqual(parser.boundaryChars, {10: true, 13: true, 45: true, 97: true, 98: true, 99: true});
|
||||
});
|
||||
|
||||
test(function parserError() {
|
||||
var boundary = 'abc',
|
||||
buffer = new Buffer(5);
|
||||
|
||||
parser.initWithBoundary(boundary);
|
||||
buffer.write('--ad', 'ascii', 0);
|
||||
assert.equal(parser.write(buffer), 3);
|
||||
});
|
||||
|
||||
test(function end() {
|
||||
(function testError() {
|
||||
assert.equal(parser.end().message, 'MultipartParser.end(): stream ended unexpectedly: ' + parser.explain());
|
||||
})();
|
||||
|
||||
(function testRegular() {
|
||||
parser.state = multipartParser.END;
|
||||
assert.strictEqual(parser.end(), undefined);
|
||||
})();
|
||||
});
|
||||
45
app/node_modules/formidable/test/legacy/simple/test-querystring-parser.js
generated
vendored
Normal file
45
app/node_modules/formidable/test/legacy/simple/test-querystring-parser.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
var common = require('../common');
|
||||
var QuerystringParser = require(common.lib + '/querystring_parser').QuerystringParser,
|
||||
Buffer = require('buffer').Buffer,
|
||||
gently,
|
||||
parser;
|
||||
|
||||
function test(test) {
|
||||
gently = new Gently();
|
||||
parser = new QuerystringParser();
|
||||
test();
|
||||
gently.verify(test.name);
|
||||
}
|
||||
|
||||
test(function constructor() {
|
||||
assert.equal(parser.buffer, '');
|
||||
assert.equal(parser.constructor.name, 'QuerystringParser');
|
||||
});
|
||||
|
||||
test(function write() {
|
||||
var a = new Buffer('a=1');
|
||||
assert.equal(parser.write(a), a.length);
|
||||
|
||||
var b = new Buffer('&b=2');
|
||||
parser.write(b);
|
||||
assert.equal(parser.buffer, a + b);
|
||||
});
|
||||
|
||||
test(function end() {
|
||||
var FIELDS = {a: ['b', {c: 'd'}], e: 'f'};
|
||||
|
||||
gently.expect(GENTLY.hijacked.querystring, 'parse', function(str) {
|
||||
assert.equal(str, parser.buffer);
|
||||
return FIELDS;
|
||||
});
|
||||
|
||||
gently.expect(parser, 'onField', Object.keys(FIELDS).length, function(key, val) {
|
||||
assert.deepEqual(FIELDS[key], val);
|
||||
});
|
||||
|
||||
gently.expect(parser, 'onEnd');
|
||||
|
||||
parser.buffer = 'my buffer';
|
||||
parser.end();
|
||||
assert.equal(parser.buffer, '');
|
||||
});
|
||||
75
app/node_modules/formidable/test/legacy/system/test-multi-video-upload.js
generated
vendored
Normal file
75
app/node_modules/formidable/test/legacy/system/test-multi-video-upload.js
generated
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
var common = require('../common');
|
||||
var BOUNDARY = '---------------------------10102754414578508781458777923',
|
||||
FIXTURE = TEST_FIXTURES+'/multi_video.upload',
|
||||
fs = require('fs'),
|
||||
util = require(common.lib + '/util'),
|
||||
http = require('http'),
|
||||
formidable = require(common.lib + '/index'),
|
||||
server = http.createServer();
|
||||
|
||||
server.on('request', function(req, res) {
|
||||
var form = new formidable.IncomingForm(),
|
||||
uploads = {};
|
||||
|
||||
form.uploadDir = TEST_TMP;
|
||||
form.hash = 'sha1';
|
||||
form.parse(req);
|
||||
|
||||
form
|
||||
.on('fileBegin', function(field, file) {
|
||||
assert.equal(field, 'upload');
|
||||
|
||||
var tracker = {file: file, progress: [], ended: false};
|
||||
uploads[file.filename] = tracker;
|
||||
file
|
||||
.on('progress', function(bytesReceived) {
|
||||
tracker.progress.push(bytesReceived);
|
||||
assert.equal(bytesReceived, file.length);
|
||||
})
|
||||
.on('end', function() {
|
||||
tracker.ended = true;
|
||||
});
|
||||
})
|
||||
.on('field', function(field, value) {
|
||||
assert.equal(field, 'title');
|
||||
assert.equal(value, '');
|
||||
})
|
||||
.on('file', function(field, file) {
|
||||
assert.equal(field, 'upload');
|
||||
assert.strictEqual(uploads[file.filename].file, file);
|
||||
})
|
||||
.on('end', function() {
|
||||
assert.ok(uploads['shortest_video.flv']);
|
||||
assert.ok(uploads['shortest_video.flv'].ended);
|
||||
assert.ok(uploads['shortest_video.flv'].progress.length > 3);
|
||||
assert.equal(uploads['shortest_video.flv'].file.hash, 'd6a17616c7143d1b1438ceeef6836d1a09186b3a');
|
||||
assert.equal(uploads['shortest_video.flv'].progress.slice(-1), uploads['shortest_video.flv'].file.length);
|
||||
assert.ok(uploads['shortest_video.mp4']);
|
||||
assert.ok(uploads['shortest_video.mp4'].ended);
|
||||
assert.ok(uploads['shortest_video.mp4'].progress.length > 3);
|
||||
assert.equal(uploads['shortest_video.mp4'].file.hash, '937dfd4db263f4887ceae19341dcc8d63bcd557f');
|
||||
|
||||
server.close();
|
||||
res.writeHead(200);
|
||||
res.end('good');
|
||||
});
|
||||
});
|
||||
|
||||
server.listen(TEST_PORT, function() {
|
||||
var client = http.createClient(TEST_PORT),
|
||||
stat = fs.statSync(FIXTURE),
|
||||
headers = {
|
||||
'content-type': 'multipart/form-data; boundary='+BOUNDARY,
|
||||
'content-length': stat.size,
|
||||
}
|
||||
request = client.request('POST', '/', headers),
|
||||
fixture = new fs.ReadStream(FIXTURE);
|
||||
|
||||
fixture
|
||||
.on('data', function(b) {
|
||||
request.write(b);
|
||||
})
|
||||
.on('end', function() {
|
||||
request.end();
|
||||
});
|
||||
});
|
||||
2
app/node_modules/formidable/test/run.js
generated
vendored
Normal file
2
app/node_modules/formidable/test/run.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env node
|
||||
require('urun')(__dirname)
|
||||
63
app/node_modules/formidable/test/unit/test-incoming-form.js
generated
vendored
Normal file
63
app/node_modules/formidable/test/unit/test-incoming-form.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
var common = require('../common');
|
||||
var test = require('utest');
|
||||
var assert = common.assert;
|
||||
var IncomingForm = common.require('incoming_form').IncomingForm;
|
||||
var path = require('path');
|
||||
|
||||
var form;
|
||||
test('IncomingForm', {
|
||||
before: function() {
|
||||
form = new IncomingForm();
|
||||
},
|
||||
|
||||
'#_fileName with regular characters': function() {
|
||||
var filename = 'foo.txt';
|
||||
assert.equal(form._fileName(makeHeader(filename)), 'foo.txt');
|
||||
},
|
||||
|
||||
'#_fileName with unescaped quote': function() {
|
||||
var filename = 'my".txt';
|
||||
assert.equal(form._fileName(makeHeader(filename)), 'my".txt');
|
||||
},
|
||||
|
||||
'#_fileName with escaped quote': function() {
|
||||
var filename = 'my%22.txt';
|
||||
assert.equal(form._fileName(makeHeader(filename)), 'my".txt');
|
||||
},
|
||||
|
||||
'#_fileName with bad quote and additional sub-header': function() {
|
||||
var filename = 'my".txt';
|
||||
var header = makeHeader(filename) + '; foo="bar"';
|
||||
assert.equal(form._fileName(header), filename);
|
||||
},
|
||||
|
||||
'#_fileName with semicolon': function() {
|
||||
var filename = 'my;.txt';
|
||||
assert.equal(form._fileName(makeHeader(filename)), 'my;.txt');
|
||||
},
|
||||
|
||||
'#_fileName with utf8 character': function() {
|
||||
var filename = 'my☃.txt';
|
||||
assert.equal(form._fileName(makeHeader(filename)), 'my☃.txt');
|
||||
},
|
||||
|
||||
'#_uploadPath strips harmful characters from extension when keepExtensions': function() {
|
||||
form.keepExtensions = true;
|
||||
|
||||
var ext = path.extname(form._uploadPath('fine.jpg?foo=bar'));
|
||||
assert.equal(ext, '.jpg');
|
||||
|
||||
var ext = path.extname(form._uploadPath('fine?foo=bar'));
|
||||
assert.equal(ext, '');
|
||||
|
||||
var ext = path.extname(form._uploadPath('super.cr2+dsad'));
|
||||
assert.equal(ext, '.cr2');
|
||||
|
||||
var ext = path.extname(form._uploadPath('super.bar'));
|
||||
assert.equal(ext, '.bar');
|
||||
},
|
||||
});
|
||||
|
||||
function makeHeader(filename) {
|
||||
return 'Content-Disposition: form-data; name="upload"; filename="' + filename + '"';
|
||||
}
|
||||
47
app/node_modules/formidable/tool/record.js
generated
vendored
Normal file
47
app/node_modules/formidable/tool/record.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
var http = require('http');
|
||||
var fs = require('fs');
|
||||
var connections = 0;
|
||||
|
||||
var server = http.createServer(function(req, res) {
|
||||
var socket = req.socket;
|
||||
console.log('Request: %s %s -> %s', req.method, req.url, socket.filename);
|
||||
|
||||
req.on('end', function() {
|
||||
if (req.url !== '/') {
|
||||
res.end(JSON.stringify({
|
||||
method: req.method,
|
||||
url: req.url,
|
||||
filename: socket.filename,
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
res.writeHead(200, {'content-type': 'text/html'});
|
||||
res.end(
|
||||
'<form action="/upload" enctype="multipart/form-data" method="post">'+
|
||||
'<input type="text" name="title"><br>'+
|
||||
'<input type="file" name="upload" multiple="multiple"><br>'+
|
||||
'<input type="submit" value="Upload">'+
|
||||
'</form>'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
server.on('connection', function(socket) {
|
||||
connections++;
|
||||
|
||||
socket.id = connections;
|
||||
socket.filename = 'connection-' + socket.id + '.http';
|
||||
socket.file = fs.createWriteStream(socket.filename);
|
||||
socket.pipe(socket.file);
|
||||
|
||||
console.log('--> %s', socket.filename);
|
||||
socket.on('close', function() {
|
||||
console.log('<-- %s', socket.filename);
|
||||
});
|
||||
});
|
||||
|
||||
var port = process.env.PORT || 8080;
|
||||
server.listen(port, function() {
|
||||
console.log('Recording connections on port %s', port);
|
||||
});
|
||||
1
app/node_modules/mongoskin/.npmignore
generated
vendored
Normal file
1
app/node_modules/mongoskin/.npmignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
47
app/node_modules/mongoskin/History.md
generated
vendored
Normal file
47
app/node_modules/mongoskin/History.md
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
0.3.4 / 2011-03-24
|
||||
* fix global leaks
|
||||
|
||||
0.3.3 / 2011-03-15
|
||||
==================
|
||||
* Add rootCollection option to SkinGridStore.exist
|
||||
|
||||
0.3.2 / 2011-03-01
|
||||
==================
|
||||
* exports all classes of node-mongodb-native
|
||||
|
||||
0.3.1 / 2011-02-26
|
||||
==================
|
||||
* bug fix #33
|
||||
|
||||
0.3.0 / 2011-01-19
|
||||
==================
|
||||
* add ReplSet support
|
||||
* bug fix
|
||||
|
||||
0.2.3 / 2011-01-03
|
||||
==================
|
||||
* add db.toObjectID
|
||||
* fix #25 for node-mongodb-native update
|
||||
|
||||
0.2.2 / 2011-12-02
|
||||
==================
|
||||
* add bind support for embeded collections, e.g. db.bind('system.js')
|
||||
* add method `toId` to SkinDB
|
||||
* add property `ObjectID`, `bson_serializer` to SkinDB.
|
||||
* SkinCollection.prototype.id is now deprecated.
|
||||
|
||||
0.2.1 / 2011-11-18
|
||||
==================
|
||||
* add ObjectId support for XXXXById
|
||||
|
||||
0.2.0 / 2011-11-06
|
||||
==================
|
||||
* add SkinDB.gridfs
|
||||
|
||||
0.1.3 / 2011-05-24
|
||||
==================
|
||||
* add SkinCollection.removeById
|
||||
|
||||
0.1.2 / 2011-04-30
|
||||
==================
|
||||
* add mongoskin.router
|
||||
570
app/node_modules/mongoskin/Readme.md
generated
vendored
Normal file
570
app/node_modules/mongoskin/Readme.md
generated
vendored
Normal file
@@ -0,0 +1,570 @@
|
||||
## This project is a wrapper of node-mongodb-native
|
||||
|
||||
* node-mongodb-native document http://christkv.github.com/node-mongodb-native/
|
||||
|
||||
## How to validate input?
|
||||
|
||||
I wrote a middleware to validate post data, [node-iform](https://github.com/guileen/node-iform)
|
||||
base on [node-validator](https://github.com/chriso/node-validator)
|
||||
|
||||
<a name='index'>
|
||||
|
||||
# Mongoskin document
|
||||
|
||||
* [Nodejs mongodb drivers comparation](#comparation)
|
||||
* [Install](#install)
|
||||
* [Quick Start](#quickstart)
|
||||
* [Connect easier](#quickstart-1)
|
||||
* [Server options and BSON options](#quickstart-2)
|
||||
* [Similar API with node-mongodb-native](#quickstart-3)
|
||||
* [Cursor easier](#quickstart-4)
|
||||
* [MVC helper](#quickstart-5)
|
||||
* [Documentation](#documentation)
|
||||
* [Module](#module)
|
||||
* [SkinServer](#skinserver)
|
||||
* [SkinDb](#skindb)
|
||||
* [SkinCollection](#skincollection)
|
||||
* [Additional methods](#additional-collection-op)
|
||||
* [Collection operation](#inherit-collection-op)
|
||||
* [Indexes](#inherit-indexes)
|
||||
* [Querying](#inherit-query)
|
||||
* [Aggregation](#inherit-aggregation)
|
||||
* [Inserting](#inherit-inserting)
|
||||
* [Updating](#inherit-updating)
|
||||
* [Removing](#inherit-removing)
|
||||
* [SkinCursor](#skincursor)
|
||||
|
||||
<a name='comparation'>
|
||||
|
||||
Nodejs Mongodb Driver Comparison
|
||||
========
|
||||
|
||||
node-mongodb-native
|
||||
--------
|
||||
|
||||
One of the most powerful Mongo drivers is node-mongodb-native. Most other drivers build
|
||||
on top of it, including mongoskin. Unfortunately, it has an awkward interface with too many
|
||||
callbacks. Also, mongoskin needs a way to hold a Collection instance as an MVC model.
|
||||
|
||||
See [mongodb-native](https://github.com/christkv/node-mongodb-native/tree/master/docs)
|
||||
|
||||
mongoose
|
||||
--------
|
||||
|
||||
Mongoose provides an ORM way to hold Collection instance as Model,
|
||||
you should define schema first. But why mongodb need schema?
|
||||
Some guys like me, want to write code from application layer but not database layer,
|
||||
and we can use any fields without define it before.
|
||||
|
||||
Mongoose provide a DAL that you can do validation, and write your middlewares.
|
||||
But some guys like me would like to validate manually, I think it is the tao of mongodb.
|
||||
|
||||
If you don't thinks so, [Mongoose-ORM](https://github.com/LearnBoost/mongoose) is probably your choice.
|
||||
|
||||
mongoskin
|
||||
--------
|
||||
|
||||
Mongoskin is an easy to use driver of mongodb for nodejs,
|
||||
it is similar with mongo shell, powerful like node-mongodb-native,
|
||||
and support additional javascript method binding, which make it can act as a Model(in document way).
|
||||
|
||||
It will provide full features of [node-mongodb-native](https://github.com/christkv/node-mongodb-native),
|
||||
and make it [future](http://en.wikipedia.org/wiki/Future_%28programming%29).
|
||||
|
||||
If you need validation, you can use [node-iform](https://github.com/guileen/node-iform).
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
<a name='install'></a>
|
||||
|
||||
Install
|
||||
========
|
||||
|
||||
npm install mongoskin
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
|
||||
<a name='quickstart'></a>
|
||||
|
||||
Quick Start
|
||||
========
|
||||
|
||||
**Is mongoskin synchronized?**
|
||||
|
||||
Nope! It is asynchronized, it use the [future pattern](http://en.wikipedia.org/wiki/Future_%28programming%29).
|
||||
**Mongoskin** is the future layer above [node-mongodb-native](https://github.com/christkv/node-mongodb-native)
|
||||
|
||||
<a name='quickstart-1'></a>
|
||||
|
||||
Connect easier
|
||||
--------
|
||||
You can connect to mongodb easier now.
|
||||
|
||||
var mongo = require('mongoskin');
|
||||
mongo.db('localhost:27017/testdb').collection('blog').find().toArray(function(err, items){
|
||||
console.dir(items);
|
||||
})
|
||||
|
||||
<a name='quickstart-2'></a>
|
||||
|
||||
Server options and BSON options
|
||||
--------
|
||||
You can also set `auto_reconnect` options querystring.
|
||||
And native_parser options will automatically set if native_parser is avariable.
|
||||
|
||||
var mongo = require('mongoskin'),
|
||||
db = mongo.db('localhost:27017/test?auto_reconnect');
|
||||
|
||||
<a name='quickstart-3'></a>
|
||||
|
||||
Similar API with node-mongodb-native
|
||||
--------
|
||||
You can do everything that node-mongodb-native can do.
|
||||
|
||||
db.createCollection(...);
|
||||
db.collection('user').ensureIndex([['username', 1]], true, function(err, replies){});
|
||||
db.collection('posts').hint = 'slug';
|
||||
db.collection('posts').findOne({slug: 'whats-up'}, function(err, post){
|
||||
// do something
|
||||
});
|
||||
|
||||
<a name='quickstart-4'></a>
|
||||
|
||||
Cursor easier
|
||||
--------
|
||||
|
||||
db.collection('posts').find().toArray(function(err, posts){
|
||||
// do something
|
||||
});
|
||||
|
||||
<a name='quickstart-5'></a>
|
||||
|
||||
MVC helper
|
||||
--------
|
||||
|
||||
You can bind **additional methods** for collection.
|
||||
It is very useful if you want to use MVC patterns with nodejs and mongodb.
|
||||
You can also invoke collection by properties after bind,
|
||||
it could simplfy your `require`.
|
||||
|
||||
db.bind('posts', {
|
||||
findTop10 : function(fn){
|
||||
this.find({}, {limit:10, sort:[['views', -1]]}).toArray(fn);
|
||||
},
|
||||
removeTagWith : function(tag, fn){
|
||||
this.remove({tags:tag},fn);
|
||||
}
|
||||
});
|
||||
|
||||
db.bind('comments');
|
||||
|
||||
db.collection('posts').removeTagWith('delete', function(err, replies){
|
||||
//do something
|
||||
});
|
||||
|
||||
db.posts.findTop10(function(err, topPosts){
|
||||
//do something
|
||||
});
|
||||
|
||||
db.comments.find().toArray(function(err, comments){
|
||||
//do something
|
||||
});
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
|
||||
<a name='documentation'>
|
||||
|
||||
Documentation
|
||||
========
|
||||
|
||||
for more information, see the source.
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
|
||||
<a name='module'>
|
||||
|
||||
Module
|
||||
--------
|
||||
|
||||
### MongoSkin Url format
|
||||
|
||||
[*://][username:password@]host[:port][/database][?auto_reconnect[=true|false]]`
|
||||
|
||||
e.g.
|
||||
|
||||
localhost/blog
|
||||
mongo://admin:pass@127.0.0.1:27017/blog?auto_reconnect
|
||||
127.0.0.1?auto_reconnect=false
|
||||
|
||||
### db(databaseUrl, db_options)
|
||||
|
||||
Get or create instance of [SkinDb](#skindb).
|
||||
|
||||
var db = mongoskin.db('localhost:27017/testdb?auto_reconnect=true&poolSize=5');
|
||||
|
||||
for ReplSet server
|
||||
|
||||
var db = mongoskin.db(['192.168.0.1:27017/?auto_reconnect=true',
|
||||
'192.168.0.2:27017/?auto_reconnect=true',
|
||||
'192.168.0.3:27017/?auto_reconnect=true'],
|
||||
{
|
||||
database: 'testdb',
|
||||
retryMiliSeconds: 2000
|
||||
})
|
||||
|
||||
### router(select)
|
||||
|
||||
select is function(collectionName) returns a database instance, means router collectionName to that database.
|
||||
|
||||
var db = mongo.router(function(coll_name){
|
||||
switch(coll_name) {
|
||||
case 'user':
|
||||
case 'message':
|
||||
return mongo.db('192.168.1.3/auth_db');
|
||||
default:
|
||||
return mongo.db('192.168.1.2/app_db');
|
||||
}
|
||||
});
|
||||
db.bind('user', require('./shared-user-methods'));
|
||||
var users = db.user; //auth_db.user
|
||||
var messages = db.collection('message'); // auth_db.message
|
||||
var products = db.collection('product'); //app_db.product
|
||||
|
||||
### classes extends frome node-mongodb-native
|
||||
|
||||
* BSONPure
|
||||
* BSONNative
|
||||
* BinaryParser
|
||||
* Binary
|
||||
* Code
|
||||
* DBRef
|
||||
* Double
|
||||
* MaxKey
|
||||
* MinKey
|
||||
* ObjectID
|
||||
* Symbol
|
||||
* Timestamp
|
||||
* Long
|
||||
* BaseCommand
|
||||
* DbCommand
|
||||
* DeleteCommand
|
||||
* GetMoreCommand
|
||||
* InsertCommand
|
||||
* KillCursorCommand
|
||||
* QueryCommand
|
||||
* UpdateCommand
|
||||
* MongoReply
|
||||
* Admin
|
||||
* Collection
|
||||
* Connection
|
||||
* Server
|
||||
* ReplSetServers
|
||||
* Cursor
|
||||
* Db
|
||||
* connect
|
||||
* Grid
|
||||
* Chunk
|
||||
* GridStore
|
||||
* native
|
||||
* pure
|
||||
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
<a name='skinserver'>
|
||||
|
||||
SkinServer
|
||||
--------
|
||||
|
||||
### SkinServer(server)
|
||||
|
||||
Construct SkinServer from native Server instance.
|
||||
|
||||
### db(dbname, username=null, password=null)
|
||||
|
||||
Construct [SkinDb](#skindb) from SkinServer.
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
<a name='skindb'>
|
||||
|
||||
SkinDb
|
||||
--------
|
||||
|
||||
### SkinDb(db, username=null, password=null)
|
||||
|
||||
Construct SkinDb.
|
||||
|
||||
### open(callback)
|
||||
|
||||
Connect to database, retrieval native
|
||||
[Db](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/db.js#L17)
|
||||
instance, callback is function(err, db).
|
||||
|
||||
### collection(collectionName)
|
||||
|
||||
Retrieval [SkinCollection](#skincollection) instance of specified collection name.
|
||||
|
||||
<a name='skindb-bind'>
|
||||
|
||||
### bind(collectionName)
|
||||
|
||||
### bind(collectionName, SkinCollection)
|
||||
|
||||
### bind(collectionName, extendObject1, extendObject2 ...)
|
||||
|
||||
Bind [SkinCollection](#skincollection) to db properties as a shortcut to db.collection(name).
|
||||
You can also bind additional methods to the SkinCollection, it is useful when
|
||||
you want to reuse a complex operation. This will also affect
|
||||
db.collection(name) method.
|
||||
|
||||
e.g.
|
||||
|
||||
db.bind('book', {
|
||||
firstBook: function(fn){
|
||||
this.findOne(fn);
|
||||
}
|
||||
});
|
||||
db.book.firstBook(function(err, book){});
|
||||
|
||||
### all the methods from Db.prototype
|
||||
|
||||
See [Db](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/db.js#L17) of node-mongodb-native for more information.
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
<a name='skincollection'>
|
||||
|
||||
SkinCollection
|
||||
--------
|
||||
|
||||
See [Collection](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L45) of node-mongodb-native for more information.
|
||||
|
||||
<a name='additional-collection-op'>
|
||||
### open(callback)
|
||||
|
||||
Retrieval native
|
||||
[Collection](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L45)
|
||||
instance, callback is function(err, collection).
|
||||
|
||||
### id(hex)
|
||||
|
||||
Equivalent to
|
||||
|
||||
db.bson_serializer.ObjectID.createFromHexString(hex);
|
||||
|
||||
See [ObjectID.createFromHexString](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/bson/bson.js#L548)
|
||||
|
||||
|
||||
<a name='inherit-collection-op'>
|
||||
|
||||
### Collection operation
|
||||
|
||||
checkCollectionName(collectionName)
|
||||
options(callback)
|
||||
rename(collectionName, callback)
|
||||
drop(callback)
|
||||
|
||||
<a name='inherit-indexes'>
|
||||
|
||||
### Indexes
|
||||
|
||||
createIndex (fieldOrSpec, unique, callback)
|
||||
ensureIndex (fieldOrSpec, unique, callback)
|
||||
indexInformation (callback)
|
||||
dropIndex (indexName, callback)
|
||||
dropIndexes (callback)
|
||||
|
||||
See [mongodb-native indexes](https://github.com/christkv/node-mongodb-native/blob/master/docs/indexes.md)
|
||||
|
||||
<a name='inherit-query'>
|
||||
|
||||
### Queries
|
||||
|
||||
See [mongodb-native queries](https://github.com/christkv/node-mongodb-native/blob/master/docs/queries.md)
|
||||
|
||||
#### findItems(..., callback)
|
||||
|
||||
Equivalent to
|
||||
|
||||
collection.find(..., function(err, cursor){
|
||||
cursor.toArray(callback);
|
||||
});
|
||||
|
||||
See [Collection.find](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L348)
|
||||
|
||||
#### findEach(..., callback)
|
||||
|
||||
Equivalent to
|
||||
|
||||
collection.find(..., function(err, cursor){
|
||||
cursor.each(callback);
|
||||
});
|
||||
|
||||
See [Collection.find](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L348)
|
||||
|
||||
#### findById(id, ..., callback)
|
||||
|
||||
Equivalent to
|
||||
|
||||
collection.findOne({_id, ObjectID.createFromHexString(id)}, ..., callback);
|
||||
|
||||
See [Collection.findOne](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L417)
|
||||
|
||||
#### find(...)
|
||||
|
||||
If the last parameter is function, it is equivalent to native
|
||||
[Collection.find](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js#L348)
|
||||
method, else it will return a future [SkinCursor](#skincursor).
|
||||
|
||||
e.g.
|
||||
|
||||
// callback
|
||||
db.book.find({}, function(err, cursor){/* do something */});
|
||||
// future SkinCursor
|
||||
db.book.find().toArray(function(err, books){/* do something */});
|
||||
|
||||
|
||||
|
||||
#### normalizeHintField(hint)
|
||||
|
||||
#### find
|
||||
|
||||
/**
|
||||
* Various argument possibilities
|
||||
* 1 callback
|
||||
* 2 selector, callback,
|
||||
* 2 callback, options // really?!
|
||||
* 3 selector, fields, callback
|
||||
* 3 selector, options, callback
|
||||
* 4,selector, fields, options, callback
|
||||
* 5 selector, fields, skip, limit, callback
|
||||
* 6 selector, fields, skip, limit, timeout, callback
|
||||
*
|
||||
* Available options:
|
||||
* limit, sort, fields, skip, hint, explain, snapshot, timeout, tailable, batchSize
|
||||
*/
|
||||
|
||||
#### findAndModify(query, sort, update, options, callback)
|
||||
|
||||
/**
|
||||
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)
|
||||
**/
|
||||
|
||||
#### findOne(queryObject, options, callback)
|
||||
|
||||
<a name='inherit-aggregation'>
|
||||
|
||||
### Aggregation
|
||||
|
||||
#### mapReduce(map, reduce, options, callback)
|
||||
|
||||
e.g. ```
|
||||
var map = function(){
|
||||
emit(test(this.timestamp.getYear()), 1);
|
||||
}
|
||||
|
||||
var reduce = function(k, v){
|
||||
count = 0;
|
||||
for(i = 0; i < v.length; i++) {
|
||||
count += v[i];
|
||||
}
|
||||
return count;
|
||||
}
|
||||
collection.mapReduce(map, reduce, {scope:{test:new client.bson_serializer.Code(t.toString())}}, function(err, collection) {
|
||||
collection.find(function(err, cursor) {
|
||||
cursor.toArray(function(err, results) {
|
||||
test.equal(2, results[0].value)
|
||||
finished_test({test_map_reduce_functions_scope:'ok'});
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
#### group(keys, condition, initial, reduce, command, callback)
|
||||
|
||||
e.g. `collection.group([], {}, {"count":0}, "function (obj, prev) { prev.count++; }", true, function(err, results) {`
|
||||
|
||||
#### count(query, callback)
|
||||
#### distinct(key, query, callback)
|
||||
|
||||
<a name='inherit-inserting'>
|
||||
|
||||
### Inserting
|
||||
|
||||
#### insert(docs, options, callback)
|
||||
|
||||
<a name='inherit-updating'>
|
||||
|
||||
### Updating
|
||||
|
||||
#### save(doc, options, callback)
|
||||
|
||||
/**
|
||||
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
|
||||
|
||||
document - an associated array with the fields to be updated or in the case of
|
||||
a upsert operation the fields to be inserted.
|
||||
|
||||
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)
|
||||
**/
|
||||
|
||||
#### update(spec, document, options, callback)
|
||||
|
||||
#### updateById(_id, ..., callback)
|
||||
|
||||
Equivalent to
|
||||
|
||||
collection.update({_id, ObjectID.createFromHexString(id)}, ..., callback);
|
||||
|
||||
See [Collection.update](https://github.com/christkv/node-mongodb-native/blob/master/docs/insert.md)
|
||||
|
||||
|
||||
<a name='inherit-removing'>
|
||||
|
||||
### Removing
|
||||
|
||||
#### remove(selector, options, callback)
|
||||
|
||||
#### removeById(_id, options, callback)
|
||||
|
||||
[Back to index](#index)
|
||||
|
||||
<a name='skincursor'>
|
||||
|
||||
SkinCursor
|
||||
---------
|
||||
|
||||
See [Cursor](https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/cursor.js#L1)
|
||||
of node-mongodb-native for more information.
|
||||
|
||||
All these methods will return the SkinCursor itself.
|
||||
|
||||
sort(keyOrList, [direction], [callback])
|
||||
limit(limit, [callback])
|
||||
skip(skip, [callback])
|
||||
batchSize(skip, [callback])
|
||||
|
||||
toArray(callback)
|
||||
each(callback)
|
||||
count(callback)
|
||||
nextObject(callback)
|
||||
getMore(callback)
|
||||
explain(callback)
|
||||
|
||||
|
||||
[Back to index](#index)
|
||||
186
app/node_modules/mongoskin/docs/docco.css
generated
vendored
Normal file
186
app/node_modules/mongoskin/docs/docco.css
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
/*--------------------- Layout and Typography ----------------------------*/
|
||||
body {
|
||||
font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
color: #252519;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
a {
|
||||
color: #261a3b;
|
||||
}
|
||||
a:visited {
|
||||
color: #261a3b;
|
||||
}
|
||||
p {
|
||||
margin: 0 0 15px 0;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin: 0px 0 15px 0;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 40px;
|
||||
}
|
||||
#container {
|
||||
position: relative;
|
||||
}
|
||||
#background {
|
||||
position: fixed;
|
||||
top: 0; left: 525px; right: 0; bottom: 0;
|
||||
background: #f5f5ff;
|
||||
border-left: 1px solid #e5e5ee;
|
||||
z-index: -1;
|
||||
}
|
||||
#jump_to, #jump_page {
|
||||
background: white;
|
||||
-webkit-box-shadow: 0 0 25px #777; -moz-box-shadow: 0 0 25px #777;
|
||||
-webkit-border-bottom-left-radius: 5px; -moz-border-radius-bottomleft: 5px;
|
||||
font: 10px Arial;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
text-align: right;
|
||||
}
|
||||
#jump_to, #jump_wrapper {
|
||||
position: fixed;
|
||||
right: 0; top: 0;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
#jump_wrapper {
|
||||
padding: 0;
|
||||
display: none;
|
||||
}
|
||||
#jump_to:hover #jump_wrapper {
|
||||
display: block;
|
||||
}
|
||||
#jump_page {
|
||||
padding: 5px 0 3px;
|
||||
margin: 0 0 25px 25px;
|
||||
}
|
||||
#jump_page .source {
|
||||
display: block;
|
||||
padding: 5px 10px;
|
||||
text-decoration: none;
|
||||
border-top: 1px solid #eee;
|
||||
}
|
||||
#jump_page .source:hover {
|
||||
background: #f5f5ff;
|
||||
}
|
||||
#jump_page .source:first-child {
|
||||
}
|
||||
table td {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
}
|
||||
td.docs, th.docs {
|
||||
max-width: 450px;
|
||||
min-width: 450px;
|
||||
min-height: 5px;
|
||||
padding: 10px 25px 1px 50px;
|
||||
overflow-x: hidden;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
.docs pre {
|
||||
margin: 15px 0 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.docs p tt, .docs p code {
|
||||
background: #f8f8ff;
|
||||
border: 1px solid #dedede;
|
||||
font-size: 12px;
|
||||
padding: 0 0.2em;
|
||||
}
|
||||
.pilwrap {
|
||||
position: relative;
|
||||
}
|
||||
.pilcrow {
|
||||
font: 12px Arial;
|
||||
text-decoration: none;
|
||||
color: #454545;
|
||||
position: absolute;
|
||||
top: 3px; left: -20px;
|
||||
padding: 1px 2px;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
}
|
||||
td.docs:hover .pilcrow {
|
||||
opacity: 1;
|
||||
}
|
||||
td.code, th.code {
|
||||
padding: 14px 15px 16px 25px;
|
||||
width: 100%;
|
||||
vertical-align: top;
|
||||
background: #f5f5ff;
|
||||
border-left: 1px solid #e5e5ee;
|
||||
}
|
||||
pre, tt, code {
|
||||
font-size: 12px; line-height: 18px;
|
||||
font-family: Monaco, Consolas, "Lucida Console", monospace;
|
||||
margin: 0; padding: 0;
|
||||
}
|
||||
|
||||
|
||||
/*---------------------- Syntax Highlighting -----------------------------*/
|
||||
td.linenos { background-color: #f0f0f0; padding-right: 10px; }
|
||||
span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
|
||||
body .hll { background-color: #ffffcc }
|
||||
body .c { color: #408080; font-style: italic } /* Comment */
|
||||
body .err { border: 1px solid #FF0000 } /* Error */
|
||||
body .k { color: #954121 } /* Keyword */
|
||||
body .o { color: #666666 } /* Operator */
|
||||
body .cm { color: #408080; font-style: italic } /* Comment.Multiline */
|
||||
body .cp { color: #BC7A00 } /* Comment.Preproc */
|
||||
body .c1 { color: #408080; font-style: italic } /* Comment.Single */
|
||||
body .cs { color: #408080; font-style: italic } /* Comment.Special */
|
||||
body .gd { color: #A00000 } /* Generic.Deleted */
|
||||
body .ge { font-style: italic } /* Generic.Emph */
|
||||
body .gr { color: #FF0000 } /* Generic.Error */
|
||||
body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
body .gi { color: #00A000 } /* Generic.Inserted */
|
||||
body .go { color: #808080 } /* Generic.Output */
|
||||
body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
|
||||
body .gs { font-weight: bold } /* Generic.Strong */
|
||||
body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
|
||||
body .gt { color: #0040D0 } /* Generic.Traceback */
|
||||
body .kc { color: #954121 } /* Keyword.Constant */
|
||||
body .kd { color: #954121; font-weight: bold } /* Keyword.Declaration */
|
||||
body .kn { color: #954121; font-weight: bold } /* Keyword.Namespace */
|
||||
body .kp { color: #954121 } /* Keyword.Pseudo */
|
||||
body .kr { color: #954121; font-weight: bold } /* Keyword.Reserved */
|
||||
body .kt { color: #B00040 } /* Keyword.Type */
|
||||
body .m { color: #666666 } /* Literal.Number */
|
||||
body .s { color: #219161 } /* Literal.String */
|
||||
body .na { color: #7D9029 } /* Name.Attribute */
|
||||
body .nb { color: #954121 } /* Name.Builtin */
|
||||
body .nc { color: #0000FF; font-weight: bold } /* Name.Class */
|
||||
body .no { color: #880000 } /* Name.Constant */
|
||||
body .nd { color: #AA22FF } /* Name.Decorator */
|
||||
body .ni { color: #999999; font-weight: bold } /* Name.Entity */
|
||||
body .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
|
||||
body .nf { color: #0000FF } /* Name.Function */
|
||||
body .nl { color: #A0A000 } /* Name.Label */
|
||||
body .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
|
||||
body .nt { color: #954121; font-weight: bold } /* Name.Tag */
|
||||
body .nv { color: #19469D } /* Name.Variable */
|
||||
body .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
|
||||
body .w { color: #bbbbbb } /* Text.Whitespace */
|
||||
body .mf { color: #666666 } /* Literal.Number.Float */
|
||||
body .mh { color: #666666 } /* Literal.Number.Hex */
|
||||
body .mi { color: #666666 } /* Literal.Number.Integer */
|
||||
body .mo { color: #666666 } /* Literal.Number.Oct */
|
||||
body .sb { color: #219161 } /* Literal.String.Backtick */
|
||||
body .sc { color: #219161 } /* Literal.String.Char */
|
||||
body .sd { color: #219161; font-style: italic } /* Literal.String.Doc */
|
||||
body .s2 { color: #219161 } /* Literal.String.Double */
|
||||
body .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
|
||||
body .sh { color: #219161 } /* Literal.String.Heredoc */
|
||||
body .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
|
||||
body .sx { color: #954121 } /* Literal.String.Other */
|
||||
body .sr { color: #BB6688 } /* Literal.String.Regex */
|
||||
body .s1 { color: #219161 } /* Literal.String.Single */
|
||||
body .ss { color: #19469D } /* Literal.String.Symbol */
|
||||
body .bp { color: #954121 } /* Name.Builtin.Pseudo */
|
||||
body .vc { color: #19469D } /* Name.Variable.Class */
|
||||
body .vg { color: #19469D } /* Name.Variable.Global */
|
||||
body .vi { color: #19469D } /* Name.Variable.Instance */
|
||||
body .il { color: #666666 } /* Literal.Number.Integer.Long */
|
||||
9
app/node_modules/mongoskin/examples/admin.js
generated
vendored
Normal file
9
app/node_modules/mongoskin/examples/admin.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
var db = require('./config').db;
|
||||
|
||||
db.admin.listDatabases(function(err, result){
|
||||
if(err) {
|
||||
console.traceError(err);
|
||||
}
|
||||
console.log(result);
|
||||
db.close();
|
||||
})
|
||||
15
app/node_modules/mongoskin/examples/close.js
generated
vendored
Normal file
15
app/node_modules/mongoskin/examples/close.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
var db = require('./config').db;
|
||||
|
||||
db.collection('test').findOne({}, function(err, data) {
|
||||
if(!err) {
|
||||
console.log('db has open');
|
||||
console.log(data);
|
||||
}
|
||||
});
|
||||
|
||||
process.on('SIGINT', function() {
|
||||
console.log('Recieve SIGINT');
|
||||
db.close(function(){
|
||||
console.log('database has closed');
|
||||
})
|
||||
})
|
||||
5
app/node_modules/mongoskin/examples/config.js
generated
vendored
Normal file
5
app/node_modules/mongoskin/examples/config.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
var mongoskin = require('../lib/mongoskin/');
|
||||
|
||||
require('myconsole').replace();
|
||||
|
||||
exports.db = mongoskin.db('localhost/test');
|
||||
31
app/node_modules/mongoskin/examples/generateId.js
generated
vendored
Normal file
31
app/node_modules/mongoskin/examples/generateId.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
var redis = require('redis').createClient()
|
||||
, shorten = require('shorten')(redis)
|
||||
, async = require('async')
|
||||
, db = require('./config').db
|
||||
;
|
||||
|
||||
db.bind('user');
|
||||
|
||||
function log(err) {
|
||||
if(err) {
|
||||
console.log(err.stack);
|
||||
}
|
||||
}
|
||||
|
||||
function createUser(user, callback) {
|
||||
|
||||
async.waterfall([
|
||||
function(fn) {
|
||||
shorten.nextId('user', fn);
|
||||
}
|
||||
, function(uid, fn) {
|
||||
user.uid = uid;
|
||||
db.user.save(user, fn);
|
||||
}
|
||||
], callback);
|
||||
|
||||
}
|
||||
|
||||
for(var i = 0; i<10; i++) {
|
||||
createUser({name: 'user' + i}, log);
|
||||
}
|
||||
13
app/node_modules/mongoskin/examples/gridfs.js
generated
vendored
Normal file
13
app/node_modules/mongoskin/examples/gridfs.js
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
var db = require('./config').db;
|
||||
|
||||
db.gridfs().open('test.txt', 'w', function(err, gs) {
|
||||
gs.write('blablabla', function(err, reply) {
|
||||
gs.close(function(err, reply){
|
||||
db.gridfs().open('test.txt', 'r' ,function(err, gs) {
|
||||
gs.read(function(err, reply){
|
||||
console.log(reply.toString());
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
8
app/node_modules/mongoskin/examples/insert.js
generated
vendored
Normal file
8
app/node_modules/mongoskin/examples/insert.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
var db = require('./config').db;
|
||||
|
||||
db.collection('test').insert({foo: 'bar'}, function(err, result) {
|
||||
console.log(result);
|
||||
db.collection('test').drop();
|
||||
db.close();
|
||||
|
||||
});
|
||||
10
app/node_modules/mongoskin/examples/replset.js
generated
vendored
Normal file
10
app/node_modules/mongoskin/examples/replset.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var mongoskin = require('../lib/mongoskin/');
|
||||
|
||||
var db = mongoskin.db(['127.0.0.1:27017'], {
|
||||
database: 'test'
|
||||
});
|
||||
|
||||
db.open(function(err, data) {
|
||||
console.log(err && err.stack);
|
||||
console.log(data);
|
||||
});
|
||||
19
app/node_modules/mongoskin/examples/update.js
generated
vendored
Normal file
19
app/node_modules/mongoskin/examples/update.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
var db = require('./config').db;
|
||||
var articles = db.collection('articles');
|
||||
articles.insert({foo: 'bar', val: 'val1'}, function(err, result) {
|
||||
|
||||
console.log(result);
|
||||
articles.update({foo:'bar'}, {foo: 'bar', val:'val2'}, {safe: true}, function(err, result) {
|
||||
|
||||
console.log(result);
|
||||
articles.find({foo: 'bar'}).toArray(function(err, docs){
|
||||
|
||||
console.log(docs);
|
||||
articles.drop();
|
||||
db.close();
|
||||
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
1
app/node_modules/mongoskin/index.js
generated
vendored
Normal file
1
app/node_modules/mongoskin/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/mongoskin');
|
||||
203
app/node_modules/mongoskin/integration/integration_tests.js
generated
vendored
Normal file
203
app/node_modules/mongoskin/integration/integration_tests.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
GLOBAL.DEBUG = true;
|
||||
|
||||
var assert = require('assert'),
|
||||
mongo = require('../lib/mongoskin');
|
||||
|
||||
console.log('======== test MongoSkin.db ========');
|
||||
(function(){
|
||||
var username = 'testuser',
|
||||
password = 'password';
|
||||
|
||||
db = mongo.db('localhost/test');
|
||||
db.open(function(err, db) {
|
||||
assert.ok(!err);
|
||||
assert.ok(db, err && err.stack);
|
||||
db.addUser(username, password, function(err, result){
|
||||
var authdb = mongo.db(username + ':' + password +'@localhost/test');
|
||||
authdb.open(function(err, db){
|
||||
assert.ok(!err, err && err.stack);
|
||||
});
|
||||
var faildb = mongo.db(username + ':wrongpassword@localhost/test');
|
||||
faildb.open(function(err, db){
|
||||
assert.ok(err, 'should not auth');
|
||||
assert.ok(!db, 'should not return db');
|
||||
});
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
||||
(function(){
|
||||
db = mongo.db('db://admin:admin@localhost:27017/test?auto_reconnect');
|
||||
db.open(function(err, db){
|
||||
assert.ok(err instanceof Error);
|
||||
})
|
||||
})();
|
||||
|
||||
var bindToBlog = {
|
||||
first: function(fn) {
|
||||
this.findOne(fn);
|
||||
}
|
||||
};
|
||||
|
||||
console.log('======== test MongoSkin.router ========');
|
||||
var testdb1 = mongo.db('localhost/test1');
|
||||
var testdb2 = mongo.db('localhost/test2');
|
||||
var router = mongo.router(function(name){
|
||||
switch(name){
|
||||
case 'user':
|
||||
case 'message':
|
||||
return testdb1;
|
||||
default:
|
||||
return testdb2;
|
||||
}
|
||||
});
|
||||
assert.equal(router.collection('user'), testdb1.collection('user'), 'user should router to testdb1');
|
||||
assert.equal(router.collection('message'), testdb1.collection('message'), 'message should router to testdb1');
|
||||
assert.equal(router.collection('others'), testdb2.collection('others'), 'others should router to testdb2');
|
||||
router.bind('user');
|
||||
router.bind('others');
|
||||
assert.equal(router.user, testdb1.user, 'user property should router to testdb1');
|
||||
assert.equal(router.others, testdb2.others, 'user property should router to testdb1');
|
||||
|
||||
console.log('======== test MongoSkin.bind ========');
|
||||
var db = mongo.db('localhost/test_mongoskin');
|
||||
db.bind('blog', bindToBlog);
|
||||
db.bind('users');
|
||||
assert.equal(db.blog.first, bindToBlog.first);
|
||||
assert.ok(db.users);
|
||||
|
||||
console.log('======== test SkinDb bson ========');
|
||||
assert.ok(db.ObjectID.createFromHexString('a7b79d4dca9d730000000000'));
|
||||
|
||||
console.log('======== test SkinDb.bind ========');
|
||||
db.bind('blog2', bindToBlog);
|
||||
db.bind('user2');
|
||||
assert.equal(db.blog2.first, bindToBlog.first);
|
||||
assert.ok(db.user2);
|
||||
|
||||
console.log('======== test SkinDb.open ========');
|
||||
(function(){
|
||||
var db1, db2;
|
||||
db.open(function(err, db) {
|
||||
assert.ok(db, err && err.stack);
|
||||
db1 = db;
|
||||
assert.equal(db1.state, 'connected');
|
||||
if (db2) {
|
||||
assert.equal(db1, db2, 'should alwayse be the same instance in db.open.');
|
||||
}
|
||||
});
|
||||
|
||||
db.open(function(err, db) {
|
||||
assert.ok(db, err && err.stack);
|
||||
db2 = db;
|
||||
assert.equal(db2.state, 'connected');
|
||||
if (db1) {
|
||||
assert.equal(db1, db2, 'should alwayse be the same instance in db.open.');
|
||||
}
|
||||
});
|
||||
|
||||
})()
|
||||
|
||||
console.log('======== test normal method of SkinDb ========');
|
||||
db.createCollection('test_createCollection', function(err, collection) {
|
||||
assert.equal(db.db.state, 'connected');
|
||||
assert.ok(collection, err && err.stack);
|
||||
});
|
||||
|
||||
|
||||
console.log('======== test SkinDb.collection ========');
|
||||
assert.equal(db.blog, db.collection('blog'));
|
||||
|
||||
console.log('======== test SkinCollection.open ========');
|
||||
var coll1, coll2;
|
||||
db.blog.open(function(err, coll) {
|
||||
assert.ok(coll, err && err.stack);
|
||||
coll1 = coll;
|
||||
if (coll2) {
|
||||
assert.equal(coll1, coll2, 'should be the same instance in collection.open');
|
||||
}
|
||||
});
|
||||
|
||||
db.blog.open(function(err, coll) {
|
||||
assert.ok(coll, err && err.stack);
|
||||
coll2 = coll;
|
||||
if (coll1) {
|
||||
assert.equal(coll1, coll2, 'should be the same instance in collection.open');
|
||||
}
|
||||
});
|
||||
|
||||
console.log('======== test normal method of SkinCollection ========');
|
||||
db.collection('test_normal').ensureIndex([['a',1]], function(err, replies){
|
||||
assert.ok(replies, err && err.stack);
|
||||
});
|
||||
|
||||
console.log('======== test SkinCollection.drop ========');
|
||||
db.collection('test_find').drop(function(err, replies){
|
||||
assert.ok(!err, err && err.stack);
|
||||
});
|
||||
|
||||
console.log('======== test SkinCollection.find ========');
|
||||
collection = db.collection('test_find');
|
||||
collection.insert([{a:1},{a:2},{a:3},{a:4}], function(err, replies){
|
||||
assert.ok(replies, err && err.stack);
|
||||
console.log('======== test SkinCollection.findById ========');
|
||||
collection.findById(replies[0]._id.toString(), function(err, item){
|
||||
assert.equal(item.a, 1);
|
||||
console.log('======== test SkinCollection.removeById ========');
|
||||
collection.removeById(replies[0]._id.toString(), function(err, reply){
|
||||
assert.ok(!err, err && err.stack);
|
||||
collection.findById(replies[0]._id.toString(), function(err, item){
|
||||
assert.ok(!err);
|
||||
assert.ok(!item);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
collection.findItems(function(err, items){
|
||||
assert.ok(items, err && err.stack);
|
||||
console.log('found '+ items.length + ' items');
|
||||
});
|
||||
collection.findEach(function(err, item){
|
||||
assert.ok(!err, err && err.stack);
|
||||
});
|
||||
collection.find(function(err, cursor){
|
||||
assert.ok(cursor, err && err.stack);
|
||||
});
|
||||
|
||||
console.log('======== test SkinCursor ========');
|
||||
collection.find().toArray(function(err, items){
|
||||
console.log('======== test find cursor toArray========');
|
||||
assert.ok(items, err && err.stack);
|
||||
});
|
||||
collection.find().each(function(err, item){
|
||||
console.log('======== test find cursor each========');
|
||||
assert.ok(!err, err && err.stack);
|
||||
});
|
||||
collection.find().sort({a:-1}).limit(2).skip(1).toArray(function(err, items){
|
||||
console.log('======== test cursor sort() limit() skip() ========');
|
||||
assert.ok(!err, err && err.stack);
|
||||
console.dir(items);
|
||||
});
|
||||
|
||||
console.log('======== deep future test ========');
|
||||
(function(){
|
||||
var db2 = mongo.db('localhost/test-mongoskin01');
|
||||
db2.collection('blog').find().toArray(function(err, items){
|
||||
assert.ok(!err, err && err.stack);
|
||||
})
|
||||
})();
|
||||
|
||||
(function(){
|
||||
var db2 = mongo.db('unknownhost/test-mongoskin01');
|
||||
db2.collection('blog').find().toArray(function(err, items){
|
||||
assert.ok(err);
|
||||
})
|
||||
})();
|
||||
/*
|
||||
console.log('======== test SkinDb.close ========');
|
||||
db.close();
|
||||
assert.equal(db.db.state, 'notConnected');
|
||||
*/
|
||||
|
||||
35
app/node_modules/mongoskin/lib/mongoskin/admin.js
generated
vendored
Normal file
35
app/node_modules/mongoskin/lib/mongoskin/admin.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
var Admin = require('mongodb').Admin
|
||||
, utils = require('./utils');
|
||||
|
||||
var SkinAdmin = exports.SkinAdmin = function(skinDb) {
|
||||
this.skinDb = skinDb;
|
||||
}
|
||||
|
||||
SkinAdmin.prototype.open = function(callback) {
|
||||
if(this.admin) return callback(null, this.admin);
|
||||
this.skinDb.open(function(err, db){
|
||||
if(err) return callback(err);
|
||||
this.admin = new Admin(db);
|
||||
callback(null, this.admin);
|
||||
})
|
||||
}
|
||||
|
||||
var bindSkin = function(name, method) {
|
||||
SkinAdmin.prototype[name] = function() {
|
||||
var args = arguments.length > 0 ? Array.prototype.slice.call(arguments, 0) : [];
|
||||
return this.open(function(err, admin) {
|
||||
if (err) {
|
||||
utils.error(err, args, 'SkinAdmin.' + name);
|
||||
} else {
|
||||
method.apply(admin, args);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
for (var name in Admin.prototype) {
|
||||
var method = Admin.prototype[name];
|
||||
bindSkin(name, method);
|
||||
}
|
||||
|
||||
exports.SkinAdmin = SkinAdmin;
|
||||
227
app/node_modules/mongoskin/lib/mongoskin/collection.js
generated
vendored
Normal file
227
app/node_modules/mongoskin/lib/mongoskin/collection.js
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
/**
|
||||
bind these methods from Collection.prototype to Provider
|
||||
|
||||
methods:
|
||||
insert
|
||||
checkCollectionName
|
||||
remove
|
||||
rename
|
||||
save
|
||||
update
|
||||
distinct
|
||||
count
|
||||
drop
|
||||
findAndModify
|
||||
find
|
||||
normalizeHintField
|
||||
findOne
|
||||
createIndex
|
||||
ensureIndex
|
||||
indexInformation
|
||||
dropIndex
|
||||
dropIndexes
|
||||
mapReduce
|
||||
group
|
||||
options
|
||||
*/
|
||||
var __slice = Array.prototype.slice,
|
||||
events = require('events'),
|
||||
Collection = require('mongodb').Collection,
|
||||
SkinCursor = require('./cursor').SkinCursor,
|
||||
utils = require('./utils'),
|
||||
STATE_CLOSE = 0,
|
||||
STATE_OPENNING = 1,
|
||||
STATE_OPEN = 2;
|
||||
|
||||
/**
|
||||
* Construct SkinCollection from SkinDb and collectionName
|
||||
* use skinDb.collection('name') usually
|
||||
*
|
||||
* @param skinDb
|
||||
* @param collectionName
|
||||
*
|
||||
*/
|
||||
var SkinCollection = exports.SkinCollection = function(skinDb, collectionName) {
|
||||
this.skinDb = skinDb;
|
||||
this.ObjectID = this.skinDb.ObjectID;
|
||||
this.collectionName = collectionName;
|
||||
this.collection;
|
||||
this.state = STATE_CLOSE;
|
||||
this.internalHint;
|
||||
var that = this;
|
||||
this.__defineGetter__('hint', function() { return this.internalHint; });
|
||||
this.__defineSetter__('hint', function(value) {
|
||||
this.internalHint = value;
|
||||
this.open(function(err, collection) {
|
||||
collection.hint = value;
|
||||
that.internalHint = collection.hint;
|
||||
});
|
||||
});
|
||||
|
||||
this.emitter = new events.EventEmitter();
|
||||
};
|
||||
|
||||
/**
|
||||
* bind method of mongodb.Collection to mongoskin.SkinCollection
|
||||
*/
|
||||
var bindSkin = function(name, method) {
|
||||
SkinCollection.prototype[name] = function() {
|
||||
var args = arguments.length > 0 ? __slice.call(arguments, 0) : [];
|
||||
this.open(function(err, collection) {
|
||||
if (err) {
|
||||
utils.error(err, args, 'SkinCollection.' + name);
|
||||
} else {
|
||||
method.apply(collection, args);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
for (var name in Collection.prototype) {
|
||||
var method = Collection.prototype[name];
|
||||
bindSkin(name, method);
|
||||
}
|
||||
|
||||
/*
|
||||
* find is a special method, because it could return a SkinCursor instance
|
||||
*/
|
||||
SkinCollection.prototype._find = SkinCollection.prototype.find;
|
||||
|
||||
/**
|
||||
* retrieve mongodb.Collection
|
||||
*/
|
||||
SkinCollection.prototype.open = function(fn) {
|
||||
switch (this.state) {
|
||||
case STATE_OPEN:
|
||||
return fn(null, this.collection);
|
||||
case STATE_OPENNING:
|
||||
return this.emitter.once('open', fn);
|
||||
case STATE_CLOSE:
|
||||
default:
|
||||
var that = this;
|
||||
this.emitter.once('open', fn);
|
||||
this.state = STATE_OPENNING;
|
||||
this.skinDb.open(function(err, db) {
|
||||
if (err) {
|
||||
that.state = STATE_CLOSE;
|
||||
return that.emitter.emit('open', err, null);
|
||||
}
|
||||
that.skinDb.db.collection(that.collectionName, function(err, collection) {
|
||||
if (collection) {
|
||||
that.state = STATE_OPEN;
|
||||
that.collection = collection;
|
||||
if (that.hint) {
|
||||
that.collection.hint = that.hit;
|
||||
}
|
||||
}else {
|
||||
that.state = STATE_CLOSE;
|
||||
}
|
||||
that.emitter.emit('open', err, collection);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
SkinCollection.prototype.close = function(){
|
||||
this.state = STATE_CLOSE;
|
||||
};
|
||||
|
||||
SkinCollection.prototype.drop = function(fn) {
|
||||
this.skinDb.dropCollection(this.collectionName, fn);
|
||||
this.close();
|
||||
};
|
||||
|
||||
/**
|
||||
* same args as find, but use Array as callback result but not use Cursor
|
||||
*
|
||||
* findItems(args, function(err, items){});
|
||||
*
|
||||
* same as
|
||||
*
|
||||
* find(args, function(err, cursor){cursor.toArray(err, items){}});
|
||||
*
|
||||
*/
|
||||
SkinCollection.prototype.findItems = function() {
|
||||
var args = __slice.call(arguments),
|
||||
fn = args[args.length - 1];
|
||||
|
||||
args[args.length - 1] = function(err, cursor) {
|
||||
if (err) {
|
||||
fn(err);
|
||||
} else {
|
||||
cursor.toArray(fn);
|
||||
}
|
||||
}
|
||||
|
||||
this._find.apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* find and cursor.each
|
||||
*/
|
||||
SkinCollection.prototype.findEach = function() {
|
||||
var args = __slice.call(arguments),
|
||||
fn = args[args.length - 1];
|
||||
|
||||
args[args.length - 1] = function(err, cursor) {
|
||||
if (err) {
|
||||
fn(err);
|
||||
} else {
|
||||
cursor.each(fn);
|
||||
}
|
||||
}
|
||||
|
||||
this._find.apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated use SkinDb.id instead
|
||||
*/
|
||||
SkinCollection.prototype.id = function(hex) {
|
||||
return this.skinDb.toId(hex);
|
||||
};
|
||||
|
||||
/**
|
||||
* use hex id as first argument, support ObjectID and String id
|
||||
*
|
||||
* @param {String/ObjectID} id
|
||||
* @param {Function} callback
|
||||
* @return {Object} cursor
|
||||
* @api public
|
||||
*/
|
||||
SkinCollection.prototype.findById = function() {
|
||||
var args = __slice.call(arguments);
|
||||
args[0] = {_id: this.skinDb.toId(args[0])};
|
||||
this.findOne.apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* use hex id as first argument
|
||||
*/
|
||||
SkinCollection.prototype.updateById = function() {
|
||||
var args = __slice.call(arguments);
|
||||
args[0] = {_id: this.skinDb.toId(args[0])};
|
||||
this.update.apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* use hex id as first argument
|
||||
*/
|
||||
SkinCollection.prototype.removeById = function() {
|
||||
var args = __slice.call(arguments);
|
||||
args[0] = {_id: this.skinDb.toId(args[0])};
|
||||
this.remove.apply(this, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* if last argument is not a function, then returns a SkinCursor
|
||||
*/
|
||||
SkinCollection.prototype.find = function() {
|
||||
var args = arguments.length > 0 ? __slice.call(arguments, 0) : [];
|
||||
if (args.length > 0 && typeof(args[args.length - 1]) === 'function') {
|
||||
this._find.apply(this, args);
|
||||
}else {
|
||||
return new SkinCursor(null, this, args);
|
||||
}
|
||||
};
|
||||
|
||||
77
app/node_modules/mongoskin/lib/mongoskin/cursor.js
generated
vendored
Normal file
77
app/node_modules/mongoskin/lib/mongoskin/cursor.js
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
var __slice = Array.prototype.slice,
|
||||
events = require('events'),
|
||||
Cursor = require('mongodb').Cursor,
|
||||
utils = require('./utils'),
|
||||
STATE_CLOSE = 0,
|
||||
STATE_OPENNING = 1,
|
||||
STATE_OPEN = 2;
|
||||
|
||||
var SkinCursor = exports.SkinCursor = function(cursor, skinCollection, args ) {
|
||||
this.cursor = cursor;
|
||||
this.skinCollection = skinCollection;
|
||||
this.args = args;
|
||||
this.emitter = new events.EventEmitter();
|
||||
if (!cursor) {
|
||||
this.state = STATE_CLOSE;
|
||||
}else {
|
||||
this.state = STATE_OPEN;
|
||||
}
|
||||
}
|
||||
|
||||
SkinCursor.prototype.open = function(fn) {
|
||||
switch (this.state) {
|
||||
case STATE_OPEN:
|
||||
return fn(null, this.cursor);
|
||||
case STATE_OPENNING:
|
||||
return this.emitter.once('open', fn);
|
||||
case STATE_CLOSE:
|
||||
default:
|
||||
var that = this;
|
||||
this.emitter.once('open', fn);
|
||||
this.state = STATE_OPENNING;
|
||||
this.skinCollection.open(function(err, collection) {
|
||||
if (err) {
|
||||
that.state = STATE_CLOSE;
|
||||
that.emitter.emit('open', err);
|
||||
return
|
||||
}
|
||||
// copy args
|
||||
var args = that.args.slice();
|
||||
args.push(function(err, cursor) {
|
||||
if (cursor) {
|
||||
that.state = STATE_OPEN;
|
||||
that.cursor = cursor;
|
||||
}
|
||||
that.emitter.emit('open', err, cursor);
|
||||
});
|
||||
|
||||
collection.find.apply(collection, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var bindSkin = function(name, method) {
|
||||
SkinCursor.prototype[name] = function() {
|
||||
var args = arguments.length > 0 ? __slice.call(arguments, 0) : [];
|
||||
this.open(function(err, cursor) {
|
||||
if (err) {
|
||||
utils.error(err, args, 'SkinCursor.' + name);
|
||||
} else {
|
||||
method.apply(cursor, args);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
};
|
||||
|
||||
[
|
||||
// callbacks
|
||||
'toArray','each','count','nextObject','getMore', 'explain',
|
||||
// self return
|
||||
'sort','limit','skip','batchSize',
|
||||
// unsupported
|
||||
//'rewind', 'close' ,...
|
||||
].forEach(function(name) {
|
||||
var method = Cursor.prototype[name];
|
||||
bindSkin(name, method);
|
||||
});
|
||||
205
app/node_modules/mongoskin/lib/mongoskin/db.js
generated
vendored
Normal file
205
app/node_modules/mongoskin/lib/mongoskin/db.js
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
var __slice = Array.prototype.slice,
|
||||
mongodb = require('mongodb'),
|
||||
events = require('events'),
|
||||
utils = require('./utils'),
|
||||
SkinAdmin = require('./admin').SkinAdmin,
|
||||
SkinCollection = require('./collection').SkinCollection,
|
||||
SkinGridStore = require('./gridfs').SkinGridStore,
|
||||
Db = mongodb.Db,
|
||||
|
||||
STATE_CLOSE = 0,
|
||||
STATE_OPENNING = 1,
|
||||
STATE_OPEN = 2;
|
||||
|
||||
var _extend = function(destination, source) {
|
||||
for (var property in source) {
|
||||
destination[property] = source[property];
|
||||
}
|
||||
return destination;
|
||||
};
|
||||
|
||||
var SkinDb = exports.SkinDb = function(db, username, password) {
|
||||
this.db = db;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.state = STATE_CLOSE;
|
||||
this.emitter = new events.EventEmitter();
|
||||
this.admin = new SkinAdmin(this);
|
||||
this._collections = {};
|
||||
this.bson_serializer = db.bson_serializer;
|
||||
this.ObjectID = mongodb.ObjectID /* 0.9.7-3-2 */ || db.bson_serializer.ObjectID /* <= 0.9.7 */;
|
||||
};
|
||||
|
||||
SkinDb.prototype.toObjectID = SkinDb.prototype.toId = function(hex) {
|
||||
if(hex instanceof this.ObjectID) {
|
||||
return hex;
|
||||
}
|
||||
return this.ObjectID.createFromHexString(hex);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* retrieve native_db
|
||||
*
|
||||
* @param fn function(err, native_db)
|
||||
*
|
||||
*/
|
||||
SkinDb.prototype.open = function(fn) {
|
||||
switch (this.state) {
|
||||
|
||||
case STATE_OPEN:
|
||||
return fn(null, this.db);
|
||||
|
||||
case STATE_OPENNING:
|
||||
// if call 'open' method multi times before opened
|
||||
return this.emitter.once('open', fn);
|
||||
|
||||
case STATE_CLOSE:
|
||||
default:
|
||||
var that = this;
|
||||
var onDbOpen = function(err, db) {
|
||||
if (!err && db) {
|
||||
that.state = STATE_OPEN;
|
||||
that.db = db;
|
||||
}else {
|
||||
db = null;
|
||||
that.state = STATE_CLOSE;
|
||||
}
|
||||
that.emitter.emit('open', err, db);
|
||||
};
|
||||
|
||||
this.emitter.once('open', fn);
|
||||
this.state = STATE_OPENNING;
|
||||
|
||||
this.db.open(function(err, db) {
|
||||
if (db && that.username) {
|
||||
//do authenticate
|
||||
db.authenticate(that.username, that.password, function(err) {
|
||||
onDbOpen(err, db);
|
||||
});
|
||||
} else {
|
||||
onDbOpen(err, db);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Close skinDb
|
||||
*/
|
||||
SkinDb.prototype.close = function(callback) {
|
||||
if (this.state === STATE_CLOSE) {
|
||||
return callback && callback();
|
||||
}else if (this.state === STATE_OPEN) {
|
||||
this.state = STATE_CLOSE;
|
||||
this.db.close(callback);
|
||||
}else if (this.state === STATE_OPENNING) {
|
||||
var that = this;
|
||||
this.emitter.once('open', function(err, db) {
|
||||
that.state = STATE_CLOSE;
|
||||
db.close(callback);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* create or retrieval skin collection
|
||||
*/
|
||||
SkinDb.prototype.collection = function(name) {
|
||||
var collection = this._collections[name];
|
||||
if (!collection) {
|
||||
this._collections[name] = collection = new SkinCollection(this, name);
|
||||
}
|
||||
return collection;
|
||||
};
|
||||
|
||||
/**
|
||||
* gridfs
|
||||
*/
|
||||
SkinDb.prototype.gridfs = function() {
|
||||
return this.skinGridStore || (this.skinGridStore = new SkinGridStore(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* bind additional method to SkinCollection
|
||||
*
|
||||
* 1. collectionName
|
||||
* 2. collectionName, extends1, extends2,... extendsn
|
||||
* 3. collectionName, SkinCollection
|
||||
*/
|
||||
SkinDb.prototype.bind = function() {
|
||||
var args = __slice.call(arguments),
|
||||
name = args[0];
|
||||
|
||||
if (typeof name !== 'string' || name.length === 0) {
|
||||
throw new Error('Must provide name parameter for bind.');
|
||||
}
|
||||
if (args.length === 1) {
|
||||
return this.bind(name, this.collection(name));
|
||||
}
|
||||
if (args.length === 2 && args[1].constructor === SkinCollection) {
|
||||
this._collections[name] = args[1];
|
||||
Object.defineProperty(this, name, {
|
||||
value: args[1],
|
||||
writable: false,
|
||||
enumerable: true
|
||||
});
|
||||
// support bind for system.js
|
||||
var names = name.split('.');
|
||||
if(names.length > 1){
|
||||
var prev = this, next;
|
||||
for(var i =0; i<names.length - 1; i++){
|
||||
next = prev[names[i]];
|
||||
if(!next){
|
||||
next = {};
|
||||
Object.defineProperty(prev, names[i], {
|
||||
value : next
|
||||
, writable : false
|
||||
, enumerable : true
|
||||
});
|
||||
}
|
||||
prev = next;
|
||||
}
|
||||
Object.defineProperty(prev, names[names.length - 1], {
|
||||
value : args[1]
|
||||
, writable : false
|
||||
, enumerable : true
|
||||
});
|
||||
}
|
||||
return args[1];
|
||||
}
|
||||
|
||||
for (var i = 1, len = args.length; i < len; i++) {
|
||||
if (typeof args[i] != 'object')
|
||||
throw new Error('the arg' + i + ' should be object, but is ' + args[i]);
|
||||
}
|
||||
|
||||
var coll = this.collection(name);
|
||||
for (var i = 0, len = args.length; i < len; i++) {
|
||||
_extend(coll, args[i]);
|
||||
}
|
||||
return this.bind(name, coll);
|
||||
};
|
||||
|
||||
var bindSkin = function(name, method) {
|
||||
return SkinDb.prototype[name] = function() {
|
||||
var args = arguments.length > 0 ? __slice.call(arguments, 0) : [];
|
||||
return this.open(function(err, db) {
|
||||
if (err) {
|
||||
utils.error(err, args, 'SkinDb.' + name);
|
||||
} else {
|
||||
return method.apply(db, args);
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
//bind method of mongodb.Db to SkinDb
|
||||
for (var name in Db.prototype) {
|
||||
if(!name || name[0] == '_' || name == 'state') continue;
|
||||
var method = Db.prototype[name];
|
||||
if (name !== 'bind' && name !== 'open' && name !== 'collection' && name !== 'admin') {
|
||||
bindSkin(name, method);
|
||||
}
|
||||
}
|
||||
|
||||
41
app/node_modules/mongoskin/lib/mongoskin/gridfs.js
generated
vendored
Normal file
41
app/node_modules/mongoskin/lib/mongoskin/gridfs.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
var GridStore = require('mongodb').GridStore;
|
||||
|
||||
/**
|
||||
* @param filename: filename or ObjectId
|
||||
*/
|
||||
var SkinGridStore = exports.SkinGridStore = function(skinDb) {
|
||||
this.skinDb = skinDb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param id
|
||||
* @param filename
|
||||
* @param mode
|
||||
* @param options
|
||||
* @param callback
|
||||
* callback(err, gridStoreObject)
|
||||
*/
|
||||
SkinGridStore.prototype.open = function(id, filename, mode, options, callback){
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var callback = args.pop();
|
||||
this.skinDb.open(function(err, db) {
|
||||
new GridStore(db, args[0], args[1], args[2], args[3]).open(callback);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filename: filename or ObjectId
|
||||
*/
|
||||
SkinGridStore.prototype.unlink = SkinGridStore.prototype.remove = function(filename, callback){
|
||||
this.skinDb.open(function(err, db) {
|
||||
GridStore.unlink(db, filename, callback);
|
||||
});
|
||||
}
|
||||
|
||||
SkinGridStore.prototype.exist = function(filename, rootCollection, callback){
|
||||
this.skinDb.open(function(err, db) {
|
||||
GridStore.exist(db, filename, rootCollection, callback);
|
||||
});
|
||||
}
|
||||
|
||||
exports.SkinGridStore = SkinGridStore;
|
||||
150
app/node_modules/mongoskin/lib/mongoskin/index.js
generated
vendored
Normal file
150
app/node_modules/mongoskin/lib/mongoskin/index.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
var url = require('url'),
|
||||
Router = require('./router').Router,
|
||||
mongo = require('mongodb'),
|
||||
SkinServer = require('./server').SkinServer,
|
||||
SkinDb =require('./db').SkinDb,
|
||||
Db = mongo.Db,
|
||||
Server = mongo.Server,
|
||||
ReplSetServers = mongo.ReplSetServers,
|
||||
BSONNative = mongo.BSONNative,
|
||||
DEFAULT_PORT = 27017;
|
||||
|
||||
function toBool(value) {
|
||||
return value !== undefined && value != 'false' && value != 'no' && value != 'off';
|
||||
}
|
||||
|
||||
/**
|
||||
* parse the database url to config
|
||||
*
|
||||
* [*://]username:password@host[:port]/database?options
|
||||
*
|
||||
*/
|
||||
var parseUrl = function(serverUrl) {
|
||||
var serverUrl = /\w+:\/\//.test(serverUrl) ? serverUrl : 'db://' + serverUrl,
|
||||
uri = url.parse(serverUrl, true),
|
||||
config = {},
|
||||
serverOptions = uri.query,
|
||||
reconnect = serverOptions['auto_reconnect'];
|
||||
|
||||
config.host = uri.hostname;
|
||||
config.port = Number(uri.port) || DEFAULT_PORT;
|
||||
if(uri.pathname) {
|
||||
config.database = uri.pathname.replace(/\//g, '');
|
||||
}
|
||||
config.options = {};
|
||||
config.options['auto_reconnect'] = toBool(serverOptions['auto_reconnect']);
|
||||
config.options['poolSize'] = parseInt(serverOptions['poolSize'] || 1);
|
||||
if (uri && uri.auth) {
|
||||
var auth = uri.auth,
|
||||
separator = auth.indexOf(':');
|
||||
config.username = auth.substr(0, separator);
|
||||
config.password = auth.substr(separator + 1);
|
||||
}
|
||||
return config;
|
||||
};
|
||||
|
||||
/**
|
||||
* constructor Server from url
|
||||
*
|
||||
*/
|
||||
var parseServer = function(serverUrl) {
|
||||
var config = parseUrl(serverUrl);
|
||||
return new Server(config.host, config.port, config.options);
|
||||
};
|
||||
|
||||
/*
|
||||
* exports mongo classes ObjectID Long Code DbRef ... to mongoskin
|
||||
*/
|
||||
for(var key in mongo) {
|
||||
exports[key] = mongo[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor SkinDb from serverUrls
|
||||
*
|
||||
* repliSet: mongoskin.db(serverUrls, rs_options, db_options)
|
||||
*
|
||||
* mongoskin.db(['192.168.0.1:27017/', '192.168.0.2/?auto_reconnect', '192.168.0.3/?auto_reconnect'], {
|
||||
* database: 'mydb'
|
||||
* })
|
||||
*
|
||||
* single Server: mongoskin.db(dbUrl, db_options)
|
||||
*
|
||||
* mongoskin.db('192.168.0.1:27017/mydb')
|
||||
*
|
||||
*/
|
||||
exports.db = function(serverUrl, options) {
|
||||
if(!options) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
var server, database;
|
||||
|
||||
if(Array.isArray(serverUrl)) {
|
||||
if(!options.database) {
|
||||
throw new Error('Please provide a database in options to connect.');
|
||||
}
|
||||
database = options.database;
|
||||
|
||||
var len = serverUrl.length;
|
||||
var servers = [];
|
||||
for(var i = 0; i < len; i++) {
|
||||
var config = parseUrl(serverUrl[i]);
|
||||
if(config.database || config.username) {
|
||||
console.log('MONGOSKIN:WARN: database or username found in RepliSet server URL, ' + serverUrl[i]);
|
||||
}
|
||||
servers.push( new Server(config.host, config.port, config.options) );
|
||||
}
|
||||
server = new ReplSetServers(servers);
|
||||
} else {
|
||||
var config = parseUrl(serverUrl);
|
||||
if (!config.database) {
|
||||
throw new Error('Please provide a database to connect to.');
|
||||
}
|
||||
database = config.database;
|
||||
|
||||
server = new Server(config.host, config.port, config.options);
|
||||
|
||||
if(options.username === undefined) {
|
||||
options.username = config.username;
|
||||
options.password = config.password;
|
||||
}
|
||||
}
|
||||
|
||||
var skinServer = new SkinServer(server);
|
||||
return skinServer.db(database, options);
|
||||
};
|
||||
|
||||
/**
|
||||
* select different db by collection name
|
||||
*
|
||||
* @param select function(name) returns SkinDb
|
||||
*
|
||||
* var router = mongoskin.router(function(name){
|
||||
* select(name){
|
||||
* case 'user':
|
||||
* case 'group':
|
||||
* return authDb;
|
||||
* default:
|
||||
* return appDb;
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* router.collection('user')
|
||||
*
|
||||
*/
|
||||
exports.router = function(select) {
|
||||
return new Router(select);
|
||||
};
|
||||
|
||||
/*
|
||||
* export Skin classes from ./db ./collection ./cursor ./admin
|
||||
*/
|
||||
['server', 'db', 'collection', 'cursor', 'admin'].forEach(function(path) {
|
||||
var foo, module, name;
|
||||
module = require('./' + path);
|
||||
for (name in module) {
|
||||
foo = module[name];
|
||||
exports[name] = foo;
|
||||
}
|
||||
});
|
||||
24
app/node_modules/mongoskin/lib/mongoskin/router.js
generated
vendored
Normal file
24
app/node_modules/mongoskin/lib/mongoskin/router.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var Router = exports.Router = function(select) {
|
||||
this._select = select;
|
||||
this._collections = {};
|
||||
}
|
||||
|
||||
Router.prototype.bind = function() {
|
||||
var args = Array.prototype.slice.call(arguments),
|
||||
name = args[0];
|
||||
|
||||
var database = this._select(name);
|
||||
var coll = database.bind.apply(database, args);
|
||||
|
||||
this._collections[name] = coll;
|
||||
Object.defineProperty(this, name, {
|
||||
value: coll,
|
||||
writable: false,
|
||||
enumerable: true
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
Router.prototype.collection = function(name) {
|
||||
return this._collections[name] || (this._collections[name] = this._select(name).collection(name));
|
||||
};
|
||||
42
app/node_modules/mongoskin/lib/mongoskin/server.js
generated
vendored
Normal file
42
app/node_modules/mongoskin/lib/mongoskin/server.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
var __slice = Array.prototype.slice,
|
||||
mongodb = require('mongodb'),
|
||||
Db = mongodb.Db,
|
||||
Server = mongodb.Server,
|
||||
SkinDb = require('./db').SkinDb;
|
||||
|
||||
/**
|
||||
* Construct SkinServer with native Server
|
||||
*
|
||||
* @param server
|
||||
*/
|
||||
var SkinServer = exports.SkinServer = function(server) {
|
||||
this.server = server;
|
||||
this._cache_ = [];
|
||||
};
|
||||
|
||||
/**
|
||||
* Create SkinDb from a SkinServer
|
||||
*
|
||||
* @param name database name
|
||||
*
|
||||
* @return SkinDb
|
||||
*
|
||||
* TODO add options
|
||||
*/
|
||||
SkinServer.prototype.db = function(name, options) {
|
||||
var key = (username || '') + '@' + name;
|
||||
var skinDb = this._cache_[key];
|
||||
if (!skinDb || skinDb.fail) {
|
||||
var username = options.username,
|
||||
password = options.password;
|
||||
delete options.username;
|
||||
delete options.password;
|
||||
if(options.native_parser === undefined) {
|
||||
options.native_parser = !! mongodb.BSONNative;
|
||||
}
|
||||
var db = new Db(name, this.server, options);
|
||||
skinDb = new SkinDb(db, username, password);
|
||||
this._cache_[key] = skinDb;
|
||||
}
|
||||
return skinDb;
|
||||
};
|
||||
8
app/node_modules/mongoskin/lib/mongoskin/utils.js
generated
vendored
Normal file
8
app/node_modules/mongoskin/lib/mongoskin/utils.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
exports.error = function(err, args, name) {
|
||||
var cb = args.pop();
|
||||
if(cb && typeof cb === 'function') {
|
||||
cb(err)
|
||||
} else {
|
||||
console.error("Error occured with no callback to handle it while calling " + name, err);
|
||||
}
|
||||
}
|
||||
5
app/node_modules/mongoskin/node_modules/mongodb/.travis.yml
generated
vendored
Normal file
5
app/node_modules/mongoskin/node_modules/mongodb/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- 0.4
|
||||
- 0.6
|
||||
- 0.7 # development version of 0.8, may be unstable
|
||||
71
app/node_modules/mongoskin/node_modules/mongodb/Makefile
generated
vendored
Normal file
71
app/node_modules/mongoskin/node_modules/mongodb/Makefile
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
NODE = node
|
||||
NPM = npm
|
||||
NODEUNIT = node_modules/nodeunit/bin/nodeunit
|
||||
DOX = node_modules/dox/bin/dox
|
||||
name = all
|
||||
|
||||
total: build_native
|
||||
|
||||
build_native:
|
||||
# $(MAKE) -C ./external-libs/bson all
|
||||
|
||||
build_native_debug:
|
||||
$(MAKE) -C ./external-libs/bson all_debug
|
||||
|
||||
build_native_clang:
|
||||
$(MAKE) -C ./external-libs/bson clang
|
||||
|
||||
build_native_clang_debug:
|
||||
$(MAKE) -C ./external-libs/bson clang_debug
|
||||
|
||||
clean_native:
|
||||
$(MAKE) -C ./external-libs/bson clean
|
||||
|
||||
test: build_native
|
||||
@echo "\n == Run All tests minus replicaset tests=="
|
||||
$(NODE) dev/tools/test_all.js --noreplicaset --boot
|
||||
|
||||
test_pure: build_native
|
||||
@echo "\n == Run All tests minus replicaset tests=="
|
||||
$(NODE) dev/tools/test_all.js --noreplicaset --boot --noactive
|
||||
|
||||
test_junit: build_native
|
||||
@echo "\n == Run All tests minus replicaset tests=="
|
||||
$(NODE) dev/tools/test_all.js --junit --noreplicaset
|
||||
|
||||
test_nodeunit_pure:
|
||||
@echo "\n == Execute Test Suite using Pure JS BSON Parser == "
|
||||
@$(NODEUNIT) test/ test/gridstore test/bson
|
||||
|
||||
test_js:
|
||||
@$(NODEUNIT) $(TESTS)
|
||||
|
||||
test_nodeunit_replicaset_pure:
|
||||
@echo "\n == Execute Test Suite using Pure JS BSON Parser == "
|
||||
@$(NODEUNIT) test/replicaset
|
||||
|
||||
test_nodeunit_native:
|
||||
@echo "\n == Execute Test Suite using Native BSON Parser == "
|
||||
@TEST_NATIVE=TRUE $(NODEUNIT) test/ test/gridstore test/bson
|
||||
|
||||
test_nodeunit_replicaset_native:
|
||||
@echo "\n == Execute Test Suite using Native BSON Parser == "
|
||||
@TEST_NATIVE=TRUE $(NODEUNIT) test/replicaset
|
||||
|
||||
test_all: build_native
|
||||
@echo "\n == Run All tests =="
|
||||
$(NODE) dev/tools/test_all.js --boot
|
||||
|
||||
test_all_junit: build_native
|
||||
@echo "\n == Run All tests =="
|
||||
$(NODE) dev/tools/test_all.js --junit --boot
|
||||
|
||||
clean:
|
||||
rm ./external-libs/bson/bson.node
|
||||
rm -r ./external-libs/bson/build
|
||||
|
||||
generate_docs:
|
||||
$(NODE) dev/tools/build-docs.js
|
||||
make --directory=./docs/sphinx-docs --file=Makefile html
|
||||
|
||||
.PHONY: total
|
||||
45
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/Makefile
generated
vendored
Normal file
45
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/Makefile
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
NODE = node
|
||||
name = all
|
||||
JOBS = 1
|
||||
|
||||
all:
|
||||
rm -rf build .lock-wscript bson.node
|
||||
node-waf configure build
|
||||
cp -R ./build/Release/bson.node . || true
|
||||
@$(NODE) --expose-gc test/test_bson.js
|
||||
@$(NODE) --expose-gc test/test_full_bson.js
|
||||
# @$(NODE) --expose-gc test/test_stackless_bson.js
|
||||
|
||||
all_debug:
|
||||
rm -rf build .lock-wscript bson.node
|
||||
node-waf --debug configure build
|
||||
cp -R ./build/Release/bson.node . || true
|
||||
@$(NODE) --expose-gc test/test_bson.js
|
||||
@$(NODE) --expose-gc test/test_full_bson.js
|
||||
# @$(NODE) --expose-gc test/test_stackless_bson.js
|
||||
|
||||
test:
|
||||
@$(NODE) --expose-gc test/test_bson.js
|
||||
@$(NODE) --expose-gc test/test_full_bson.js
|
||||
# @$(NODE) --expose-gc test/test_stackless_bson.js
|
||||
|
||||
clang:
|
||||
rm -rf build .lock-wscript bson.node
|
||||
CXX=clang node-waf configure build
|
||||
cp -R ./build/Release/bson.node . || true
|
||||
@$(NODE) --expose-gc test/test_bson.js
|
||||
@$(NODE) --expose-gc test/test_full_bson.js
|
||||
# @$(NODE) --expose-gc test/test_stackless_bson.js
|
||||
|
||||
clang_debug:
|
||||
rm -rf build .lock-wscript bson.node
|
||||
CXX=clang node-waf --debug configure build
|
||||
cp -R ./build/Release/bson.node . || true
|
||||
@$(NODE) --expose-gc test/test_bson.js
|
||||
@$(NODE) --expose-gc test/test_full_bson.js
|
||||
# @$(NODE) --expose-gc test/test_stackless_bson.js
|
||||
|
||||
clean:
|
||||
rm -rf build .lock-wscript bson.node
|
||||
|
||||
.PHONY: all
|
||||
2165
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/bson.cc
generated
vendored
Normal file
2165
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/bson.cc
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
105
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/bson.h
generated
vendored
Normal file
105
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/bson.h
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
#ifndef BSON_H_
|
||||
#define BSON_H_
|
||||
|
||||
#include <node.h>
|
||||
#include <node_object_wrap.h>
|
||||
#include <v8.h>
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
class BSON : public ObjectWrap {
|
||||
public:
|
||||
BSON() : ObjectWrap() {}
|
||||
~BSON() {}
|
||||
|
||||
static void Initialize(Handle<Object> target);
|
||||
static Handle<Value> BSONDeserializeStream(const Arguments &args);
|
||||
|
||||
// JS based objects
|
||||
static Handle<Value> BSONSerialize(const Arguments &args);
|
||||
static Handle<Value> BSONDeserialize(const Arguments &args);
|
||||
|
||||
// Calculate size of function
|
||||
static Handle<Value> CalculateObjectSize(const Arguments &args);
|
||||
static Handle<Value> SerializeWithBufferAndIndex(const Arguments &args);
|
||||
|
||||
// Experimental
|
||||
static Handle<Value> CalculateObjectSize2(const Arguments &args);
|
||||
static Handle<Value> BSONSerialize2(const Arguments &args);
|
||||
|
||||
// Constructor used for creating new BSON objects from C++
|
||||
static Persistent<FunctionTemplate> constructor_template;
|
||||
|
||||
private:
|
||||
static Handle<Value> New(const Arguments &args);
|
||||
static Handle<Value> deserialize(BSON *bson, char *data, uint32_t dataLength, uint32_t startIndex, bool is_array_item);
|
||||
static uint32_t serialize(BSON *bson, char *serialized_object, uint32_t index, Handle<Value> name, Handle<Value> value, bool check_key, bool serializeFunctions);
|
||||
|
||||
static char* extract_string(char *data, uint32_t offset);
|
||||
static const char* ToCString(const v8::String::Utf8Value& value);
|
||||
static uint32_t calculate_object_size(BSON *bson, Handle<Value> object, bool serializeFunctions);
|
||||
|
||||
static void write_int32(char *data, uint32_t value);
|
||||
static void write_int64(char *data, int64_t value);
|
||||
static void write_double(char *data, double value);
|
||||
static uint16_t deserialize_int8(char *data, uint32_t offset);
|
||||
static uint32_t deserialize_int32(char* data, uint32_t offset);
|
||||
static char *check_key(Local<String> key);
|
||||
|
||||
// BSON type instantiate functions
|
||||
Persistent<Function> longConstructor;
|
||||
Persistent<Function> objectIDConstructor;
|
||||
Persistent<Function> binaryConstructor;
|
||||
Persistent<Function> codeConstructor;
|
||||
Persistent<Function> dbrefConstructor;
|
||||
Persistent<Function> symbolConstructor;
|
||||
Persistent<Function> doubleConstructor;
|
||||
Persistent<Function> timestampConstructor;
|
||||
Persistent<Function> minKeyConstructor;
|
||||
Persistent<Function> maxKeyConstructor;
|
||||
|
||||
// Equality Objects
|
||||
Persistent<String> longString;
|
||||
Persistent<String> objectIDString;
|
||||
Persistent<String> binaryString;
|
||||
Persistent<String> codeString;
|
||||
Persistent<String> dbrefString;
|
||||
Persistent<String> symbolString;
|
||||
Persistent<String> doubleString;
|
||||
Persistent<String> timestampString;
|
||||
Persistent<String> minKeyString;
|
||||
Persistent<String> maxKeyString;
|
||||
|
||||
// Equality speed up comparision objects
|
||||
Persistent<String> _bsontypeString;
|
||||
Persistent<String> _longLowString;
|
||||
Persistent<String> _longHighString;
|
||||
Persistent<String> _objectIDidString;
|
||||
Persistent<String> _binaryPositionString;
|
||||
Persistent<String> _binarySubTypeString;
|
||||
Persistent<String> _binaryBufferString;
|
||||
Persistent<String> _doubleValueString;
|
||||
Persistent<String> _symbolValueString;
|
||||
|
||||
Persistent<String> _dbRefRefString;
|
||||
Persistent<String> _dbRefIdRefString;
|
||||
Persistent<String> _dbRefDbRefString;
|
||||
Persistent<String> _dbRefNamespaceString;
|
||||
Persistent<String> _dbRefDbString;
|
||||
Persistent<String> _dbRefOidString;
|
||||
|
||||
// Decode JS function
|
||||
static Handle<Value> decodeLong(BSON *bson, char *data, uint32_t index);
|
||||
static Handle<Value> decodeTimestamp(BSON *bson, char *data, uint32_t index);
|
||||
static Handle<Value> decodeOid(BSON *bson, char *oid);
|
||||
static Handle<Value> decodeBinary(BSON *bson, uint32_t sub_type, uint32_t number_of_bytes, char *data);
|
||||
static Handle<Value> decodeCode(BSON *bson, char *code, Handle<Value> scope);
|
||||
static Handle<Value> decodeDBref(BSON *bson, Local<Value> ref, Local<Value> oid, Local<Value> db);
|
||||
|
||||
// Experimental
|
||||
static uint32_t calculate_object_size2(Handle<Value> object);
|
||||
static uint32_t serialize2(char *serialized_object, uint32_t index, Handle<Value> name, Handle<Value> value, uint32_t object_size, bool check_key);
|
||||
};
|
||||
|
||||
#endif // BSON_H_
|
||||
20
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/index.js
generated
vendored
Normal file
20
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/index.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
var bson = require('./bson');
|
||||
exports.BSON = bson.BSON;
|
||||
exports.Long = require('../../lib/mongodb/bson/long').Long;
|
||||
exports.ObjectID = require('../../lib/mongodb/bson/objectid').ObjectID;
|
||||
exports.DBRef = require('../../lib/mongodb/bson/db_ref').DBRef;
|
||||
exports.Code = require('../../lib/mongodb/bson/code').Code;
|
||||
exports.Timestamp = require('../../lib/mongodb/bson/timestamp').Timestamp;
|
||||
exports.Binary = require('../../lib/mongodb/bson/binary').Binary;
|
||||
exports.Double = require('../../lib/mongodb/bson/double').Double;
|
||||
exports.MaxKey = require('../../lib/mongodb/bson/max_key').MaxKey;
|
||||
exports.MinKey = require('../../lib/mongodb/bson/min_key').MinKey;
|
||||
exports.Symbol = require('../../lib/mongodb/bson/symbol').Symbol;
|
||||
|
||||
// Just add constants tot he Native BSON parser
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_FUNCTION = 1;
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_UUID = 3;
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_MD5 = 4;
|
||||
exports.BSON.BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
|
||||
349
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_bson.js
generated
vendored
Normal file
349
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_bson.js
generated
vendored
Normal file
@@ -0,0 +1,349 @@
|
||||
var sys = require('util'),
|
||||
debug = require('util').debug,
|
||||
inspect = require('util').inspect,
|
||||
Buffer = require('buffer').Buffer,
|
||||
BSON = require('../bson').BSON,
|
||||
Buffer = require('buffer').Buffer,
|
||||
BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
|
||||
BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
|
||||
Long = require('../../../lib/mongodb/bson/long').Long,
|
||||
ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
|
||||
Binary = require('../../../lib/mongodb/bson/bson').Binary,
|
||||
Code = require('../../../lib/mongodb/bson/bson').Code,
|
||||
DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
|
||||
Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
|
||||
Double = require('../../../lib/mongodb/bson/bson').Double,
|
||||
MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
|
||||
MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
|
||||
Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp,
|
||||
assert = require('assert');
|
||||
|
||||
if(process.env['npm_package_config_native'] != null) return;
|
||||
|
||||
sys.puts("=== EXECUTING TEST_BSON ===");
|
||||
|
||||
// Should fail due to illegal key
|
||||
assert.throws(function() { new ObjectID('foo'); })
|
||||
assert.throws(function() { new ObjectID('foo'); })
|
||||
|
||||
// Parsers
|
||||
var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
|
||||
// Simple serialization and deserialization of edge value
|
||||
var doc = {doc:0x1ffffffffffffe};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
var doc = {doc:-0x1ffffffffffffe};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
//
|
||||
// Assert correct toJSON
|
||||
//
|
||||
var a = Long.fromNumber(10);
|
||||
assert.equal(10, a);
|
||||
|
||||
var a = Long.fromNumber(9223372036854775807);
|
||||
assert.equal(9223372036854775807, a);
|
||||
|
||||
// Simple serialization and deserialization test for a Single String value
|
||||
var doc = {doc:'Serialize'};
|
||||
var simple_string_serialized = bsonC.serialize(doc, true, false);
|
||||
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Nested doc
|
||||
var doc = {a:{b:{c:1}}};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple integer serialization/deserialization test, including testing boundary conditions
|
||||
var doc = {doc:-1};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
var doc = {doc:2147483648};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
var doc = {doc:-2147483648};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization test for a Long value
|
||||
var doc = {doc:Long.fromNumber(9223372036854775807)};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Long.fromNumber(9223372036854775807)}, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
var doc = {doc:Long.fromNumber(-9223372036854775807)};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Long.fromNumber(-9223372036854775807)}, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization for a Float value
|
||||
var doc = {doc:2222.3333};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
var doc = {doc:-2222.3333};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization for a null value
|
||||
var doc = {doc:null};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization for a boolean value
|
||||
var doc = {doc:true};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization for a date value
|
||||
var date = new Date();
|
||||
var doc = {doc:date};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')), bsonC.deserialize(simple_string_serialized));
|
||||
|
||||
// Simple serialization and deserialization for a boolean value
|
||||
var doc = {doc:/abcd/mi};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.equal(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
|
||||
|
||||
var doc = {doc:/abcd/};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc, false, true));
|
||||
assert.equal(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
|
||||
|
||||
// Simple serialization and deserialization for a objectId value
|
||||
var doc = {doc:new ObjectID()};
|
||||
var simple_string_serialized = bsonC.serialize(doc, false, true);
|
||||
var doc2 = {doc:ObjectID.createFromHexString(doc.doc.toHexString())};
|
||||
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize(doc2, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.toString(), bsonC.deserialize(simple_string_serialized).doc.toString());
|
||||
|
||||
// Simple serialization and deserialization for a Binary value
|
||||
var binary = new Binary();
|
||||
var string = 'binstring'
|
||||
for(var index = 0; index < string.length; index++) { binary.put(string.charAt(index)); }
|
||||
|
||||
var Binary = new Binary();
|
||||
var string = 'binstring'
|
||||
for(var index = 0; index < string.length; index++) { Binary.put(string.charAt(index)); }
|
||||
|
||||
var simple_string_serialized = bsonC.serialize({doc:binary}, false, true);
|
||||
assert.deepEqual(simple_string_serialized, bsonJS.serialize({doc:Binary}, false, true));
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized, 'binary')).doc.value(), bsonC.deserialize(simple_string_serialized).doc.value());
|
||||
|
||||
// Simple serialization and deserialization for a Code value
|
||||
var code = new Code('this.a > i', {'i': 1});
|
||||
var Code = new Code('this.a > i', {'i': 1});
|
||||
var simple_string_serialized_2 = bsonJS.serialize({doc:Code}, false, true);
|
||||
var simple_string_serialized = bsonC.serialize({doc:code}, false, true);
|
||||
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2);
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc.scope, bsonC.deserialize(simple_string_serialized).doc.scope);
|
||||
|
||||
// Simple serialization and deserialization for an Object
|
||||
var simple_string_serialized = bsonC.serialize({doc:{a:1, b:{c:2}}}, false, true);
|
||||
var simple_string_serialized_2 = bsonJS.serialize({doc:{a:1, b:{c:2}}}, false, true);
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, bsonC.deserialize(simple_string_serialized).doc);
|
||||
|
||||
// Simple serialization and deserialization for an Array
|
||||
var simple_string_serialized = bsonC.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true);
|
||||
var simple_string_serialized_2 = bsonJS.serialize({doc:[9, 9, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1]}, false, true);
|
||||
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
|
||||
assert.deepEqual(bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary')).doc, bsonC.deserialize(simple_string_serialized).doc);
|
||||
|
||||
// Simple serialization and deserialization for a DBRef
|
||||
var oid = new ObjectID()
|
||||
var oid2 = new ObjectID.createFromHexString(oid.toHexString())
|
||||
var simple_string_serialized = bsonJS.serialize({doc:new DBRef('namespace', oid2, 'integration_tests_')}, false, true);
|
||||
var simple_string_serialized_2 = bsonC.serialize({doc:new DBRef('namespace', oid, 'integration_tests_')}, false, true);
|
||||
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
|
||||
// Ensure we have the same values for the dbref
|
||||
var object_js = bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary'));
|
||||
var object_c = bsonC.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 = bsonC.deserialize(new Buffer(serialized_data, 'binary'));
|
||||
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 = bsonC.serialize(doc, false, true);
|
||||
var simple_string_serialized2 = bsonJS.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized2)
|
||||
|
||||
var object = bsonC.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 = bsonC.serialize(doc, false, true);
|
||||
var simple_string_serialized_2 = bsonJS.serialize(doc, false, true);
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
|
||||
|
||||
var object = bsonC.deserialize(simple_string_serialized);
|
||||
assert.deepEqual(doc, object)
|
||||
|
||||
// Test equality of an object ID
|
||||
var object_id = new ObjectID();
|
||||
var object_id_2 = new ObjectID();
|
||||
assert.ok(object_id.equals(object_id));
|
||||
assert.ok(!(object_id.equals(object_id_2)))
|
||||
|
||||
// Test same serialization for Object ID
|
||||
var object_id = new ObjectID();
|
||||
var object_id2 = ObjectID.createFromHexString(object_id.toString())
|
||||
var simple_string_serialized = bsonJS.serialize({doc:object_id}, false, true);
|
||||
var simple_string_serialized_2 = bsonC.serialize({doc:object_id2}, false, true);
|
||||
|
||||
assert.equal(simple_string_serialized_2.length, simple_string_serialized.length);
|
||||
assert.deepEqual(simple_string_serialized, simple_string_serialized_2)
|
||||
var object = bsonJS.deserialize(new Buffer(simple_string_serialized_2, 'binary'));
|
||||
var object2 = bsonC.deserialize(simple_string_serialized);
|
||||
assert.equal(object.doc.id, object2.doc.id)
|
||||
|
||||
// JS Object
|
||||
var c1 = { _id: new ObjectID, comments: [], title: 'number 1' };
|
||||
var c2 = { _id: new ObjectID, comments: [], title: 'number 2' };
|
||||
var doc = {
|
||||
numbers: []
|
||||
, owners: []
|
||||
, comments: [c1, c2]
|
||||
, _id: new ObjectID
|
||||
};
|
||||
|
||||
var simple_string_serialized = bsonJS.serialize(doc, false, true);
|
||||
|
||||
// C++ Object
|
||||
var c1 = { _id: ObjectID.createFromHexString(c1._id.toHexString()), comments: [], title: 'number 1' };
|
||||
var c2 = { _id: ObjectID.createFromHexString(c2._id.toHexString()), comments: [], title: 'number 2' };
|
||||
var doc = {
|
||||
numbers: []
|
||||
, owners: []
|
||||
, comments: [c1, c2]
|
||||
, _id: ObjectID.createFromHexString(doc._id.toHexString())
|
||||
};
|
||||
|
||||
var simple_string_serialized_2 = bsonC.serialize(doc, false, true);
|
||||
|
||||
for(var i = 0; i < simple_string_serialized_2.length; i++) {
|
||||
// debug(i + "[" + simple_string_serialized_2[i] + "] = [" + simple_string_serialized[i] + "]")
|
||||
assert.equal(simple_string_serialized_2[i], simple_string_serialized[i]);
|
||||
}
|
||||
|
||||
// Deserialize the string
|
||||
var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
|
||||
var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
|
||||
assert.equal(doc._id.id, doc1._id.id)
|
||||
assert.equal(doc._id.id, doc2._id.id)
|
||||
assert.equal(doc1._id.id, doc2._id.id)
|
||||
|
||||
var doc = {
|
||||
_id: 'testid',
|
||||
key1: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 },
|
||||
key2: { code: 'test1', time: {start:1309323402727,end:1309323402727}, x:10, y:5 }
|
||||
};
|
||||
|
||||
var simple_string_serialized = bsonJS.serialize(doc, false, true);
|
||||
var simple_string_serialized_2 = bsonC.serialize(doc, false, true);
|
||||
|
||||
// Deserialize the string
|
||||
var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
|
||||
var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
|
||||
assert.deepEqual(doc2, doc1)
|
||||
assert.deepEqual(doc, doc2)
|
||||
assert.deepEqual(doc, doc1)
|
||||
|
||||
// Serialize function
|
||||
var doc = {
|
||||
_id: 'testid',
|
||||
key1: function() {}
|
||||
}
|
||||
|
||||
var simple_string_serialized = bsonJS.serialize(doc, false, true, true);
|
||||
var simple_string_serialized_2 = bsonC.serialize(doc, false, true, true);
|
||||
|
||||
// Deserialize the string
|
||||
var doc1 = bsonJS.deserialize(new Buffer(simple_string_serialized_2));
|
||||
var doc2 = bsonC.deserialize(new Buffer(simple_string_serialized_2));
|
||||
assert.equal(doc1.key1.code.toString(), doc2.key1.code.toString())
|
||||
|
||||
var doc = {"user_id":"4e9fc8d55883d90100000003","lc_status":{"$ne":"deleted"},"owner_rating":{"$exists":false}};
|
||||
var simple_string_serialized = bsonJS.serialize(doc, false, true, true);
|
||||
var simple_string_serialized_2 = bsonC.serialize(doc, false, true, true);
|
||||
|
||||
// Should serialize to the same value
|
||||
assert.equal(simple_string_serialized_2.toString('base64'), simple_string_serialized.toString('base64'))
|
||||
var doc1 = bsonJS.deserialize(simple_string_serialized_2);
|
||||
var doc2 = bsonC.deserialize(simple_string_serialized);
|
||||
assert.deepEqual(doc1, doc2)
|
||||
|
||||
// Hex Id
|
||||
var hexId = new ObjectID().toString();
|
||||
var docJS = {_id: ObjectID.createFromHexString(hexId), 'funds.remaining': {$gte: 1.222}, 'transactions.id': {$ne: ObjectID.createFromHexString(hexId)}};
|
||||
var docC = {_id: ObjectID.createFromHexString(hexId), 'funds.remaining': {$gte: 1.222}, 'transactions.id': {$ne: ObjectID.createFromHexString(hexId)}};
|
||||
var docJSBin = bsonJS.serialize(docJS, false, true, true);
|
||||
var docCBin = bsonC.serialize(docC, false, true, true);
|
||||
assert.equal(docCBin.toString('base64'), docJSBin.toString('base64'));
|
||||
|
||||
// // Complex document serialization
|
||||
// doc = {"DateTime": "Tue Nov 40 2011 17:27:55 GMT+0000 (WEST)","isActive": true,"Media": {"URL": "http://videos.sapo.pt/Tc85NsjaKjj8o5aV7Ubb"},"Title": "Lisboa fecha a ganhar 0.19%","SetPosition": 60,"Type": "videos","Thumbnail": [{"URL": "http://rd3.videos.sapo.pt/Tc85NsjaKjj8o5aV7Ubb/pic/320x240","Dimensions": {"Height": 240,"Width": 320}}],"Source": {"URL": "http://videos.sapo.pt","SetID": "1288","SourceID": "http://videos.sapo.pt/tvnet/rss2","SetURL": "http://noticias.sapo.pt/videos/tv-net_1288/","ItemID": "Tc85NsjaKjj8o5aV7Ubb","Name": "SAPO VÃdeos"},"Category": "Tec_ciencia","Description": "Lisboa fecha a ganhar 0.19%","GalleryID": new ObjectID("4eea2a634ce8573200000000"),"InternalRefs": {"RegisterDate": "Thu Dec 15 2011 17:12:51 GMT+0000 (WEST)","ChangeDate": "Thu Dec 15 2011 17:12:51 GMT+0000 (WEST)","Hash": 332279244514},"_id": new ObjectID("4eea2a96e52778160000003a")}
|
||||
// var docJSBin = bsonJS.serialize(docJS, false, true, true);
|
||||
// var docCBin = bsonC.serialize(docC, false, true, true);
|
||||
//
|
||||
//
|
||||
|
||||
// // Force garbage collect
|
||||
// global.gc();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
218
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_full_bson.js
generated
vendored
Normal file
218
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_full_bson.js
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
var sys = require('util'),
|
||||
fs = require('fs'),
|
||||
Buffer = require('buffer').Buffer,
|
||||
BSON = require('../bson').BSON,
|
||||
Buffer = require('buffer').Buffer,
|
||||
assert = require('assert'),
|
||||
BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
|
||||
BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
|
||||
Long = require('../../../lib/mongodb/bson/long').Long,
|
||||
ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
|
||||
Binary = require('../../../lib/mongodb/bson/bson').Binary,
|
||||
Code = require('../../../lib/mongodb/bson/bson').Code,
|
||||
DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
|
||||
Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
|
||||
Double = require('../../../lib/mongodb/bson/bson').Double,
|
||||
MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
|
||||
MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
|
||||
Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp;
|
||||
|
||||
if(process.env['npm_package_config_native'] != null) return;
|
||||
|
||||
sys.puts("=== EXECUTING TEST_FULL_BSON ===");
|
||||
|
||||
// Parsers
|
||||
var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
|
||||
// Should Correctly Deserialize object
|
||||
var bytes = [95,0,0,0,2,110,115,0,42,0,0,0,105,110,116,101,103,114,97,116,105,111,110,95,116,101,115,116,115,95,46,116,101,115,116,95,105,110,100,101,120,95,105,110,102,111,114,109,97,116,105,111,110,0,8,117,110,105,113,117,101,0,0,3,107,101,121,0,12,0,0,0,16,97,0,1,0,0,0,0,2,110,97,109,101,0,4,0,0,0,97,95,49,0,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 = bsonC.deserialize(serialized_data);
|
||||
assert.equal("a_1", object.name);
|
||||
assert.equal(false, object.unique);
|
||||
assert.equal(1, object.key.a);
|
||||
|
||||
// Should Correctly Deserialize object with all types
|
||||
var bytes = [26,1,0,0,7,95,105,100,0,161,190,98,75,118,169,3,0,0,3,0,0,4,97,114,114,97,121,0,26,0,0,0,16,48,0,1,0,0,0,16,49,0,2,0,0,0,16,50,0,3,0,0,0,0,2,115,116,114,105,110,103,0,6,0,0,0,104,101,108,108,111,0,3,104,97,115,104,0,19,0,0,0,16,97,0,1,0,0,0,16,98,0,2,0,0,0,0,9,100,97,116,101,0,161,190,98,75,0,0,0,0,7,111,105,100,0,161,190,98,75,90,217,18,0,0,1,0,0,5,98,105,110,97,114,121,0,7,0,0,0,2,3,0,0,0,49,50,51,16,105,110,116,0,42,0,0,0,1,102,108,111,97,116,0,223,224,11,147,169,170,64,64,11,114,101,103,101,120,112,0,102,111,111,98,97,114,0,105,0,8,98,111,111,108,101,97,110,0,1,15,119,104,101,114,101,0,25,0,0,0,12,0,0,0,116,104,105,115,46,120,32,61,61,32,51,0,5,0,0,0,0,3,100,98,114,101,102,0,37,0,0,0,2,36,114,101,102,0,5,0,0,0,116,101,115,116,0,7,36,105,100,0,161,190,98,75,2,180,1,0,0,2,0,0,0,10,110,117,108,108,0,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 = bsonJS.deserialize(new Buffer(serialized_data, 'binary'));
|
||||
assert.equal("hello", object.string);
|
||||
assert.deepEqual([1, 2, 3], object.array);
|
||||
assert.equal(1, object.hash.a);
|
||||
assert.equal(2, object.hash.b);
|
||||
assert.ok(object.date != null);
|
||||
assert.ok(object.oid != null);
|
||||
assert.ok(object.binary != null);
|
||||
assert.equal(42, object.int);
|
||||
assert.equal(33.3333, object.float);
|
||||
assert.ok(object.regexp != null);
|
||||
assert.equal(true, object.boolean);
|
||||
assert.ok(object.where != null);
|
||||
assert.ok(object.dbref != null);
|
||||
assert.ok(object['null'] == null);
|
||||
|
||||
// Should Serialize and Deserialze String
|
||||
var test_string = {hello: 'world'}
|
||||
var serialized_data = bsonC.serialize(test_string)
|
||||
assert.deepEqual(test_string, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Integer
|
||||
var test_number = {doc: 5}
|
||||
var serialized_data = bsonC.serialize(test_number)
|
||||
assert.deepEqual(test_number, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize null value
|
||||
var test_null = {doc:null}
|
||||
var serialized_data = bsonC.serialize(test_null)
|
||||
var object = bsonC.deserialize(serialized_data);
|
||||
assert.deepEqual(test_null, object);
|
||||
|
||||
// Should Correctly Serialize and Deserialize undefined value
|
||||
var test_undefined = {doc:undefined}
|
||||
var serialized_data = bsonC.serialize(test_undefined)
|
||||
var object = bsonJS.deserialize(new Buffer(serialized_data, 'binary'));
|
||||
assert.equal(null, object.doc)
|
||||
|
||||
// Should Correctly Serialize and Deserialize Number
|
||||
var test_number = {doc: 5.5}
|
||||
var serialized_data = bsonC.serialize(test_number)
|
||||
assert.deepEqual(test_number, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Integer
|
||||
var test_int = {doc: 42}
|
||||
var serialized_data = bsonC.serialize(test_int)
|
||||
assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
|
||||
|
||||
test_int = {doc: -5600}
|
||||
serialized_data = bsonC.serialize(test_int)
|
||||
assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
|
||||
|
||||
test_int = {doc: 2147483647}
|
||||
serialized_data = bsonC.serialize(test_int)
|
||||
assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
|
||||
|
||||
test_int = {doc: -2147483648}
|
||||
serialized_data = bsonC.serialize(test_int)
|
||||
assert.deepEqual(test_int, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Object
|
||||
var doc = {doc: {age: 42, name: 'Spongebob', shoe_size: 9.5}}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Array
|
||||
var doc = {doc: [1, 2, 'a', 'b']}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Array with added on functions
|
||||
var doc = {doc: [1, 2, 'a', 'b']}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize A Boolean
|
||||
var doc = {doc: true}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize a Date
|
||||
var date = new Date()
|
||||
//(2009, 11, 12, 12, 00, 30)
|
||||
date.setUTCDate(12)
|
||||
date.setUTCFullYear(2009)
|
||||
date.setUTCMonth(11 - 1)
|
||||
date.setUTCHours(12)
|
||||
date.setUTCMinutes(0)
|
||||
date.setUTCSeconds(30)
|
||||
var doc = {doc: date}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc, bsonC.deserialize(serialized_data));
|
||||
|
||||
// // Should Correctly Serialize and Deserialize Oid
|
||||
var doc = {doc: new ObjectID()}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
assert.deepEqual(doc.doc.toHexString(), bsonC.deserialize(serialized_data).doc.toHexString())
|
||||
|
||||
// Should Correctly encode Empty Hash
|
||||
var test_code = {}
|
||||
var serialized_data = bsonC.serialize(test_code)
|
||||
assert.deepEqual(test_code, bsonC.deserialize(serialized_data));
|
||||
|
||||
// Should Correctly Serialize and Deserialize Ordered Hash
|
||||
var doc = {doc: {b:1, a:2, c:3, d:4}}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
var decoded_hash = bsonC.deserialize(serialized_data).doc
|
||||
var keys = []
|
||||
for(name in decoded_hash) keys.push(name)
|
||||
assert.deepEqual(['b', 'a', 'c', 'd'], keys)
|
||||
|
||||
// Should Correctly Serialize and Deserialize Regular Expression
|
||||
// Serialize the regular expression
|
||||
var doc = {doc: /foobar/mi}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
var doc2 = bsonC.deserialize(serialized_data);
|
||||
assert.equal(doc.doc.toString(), doc2.doc.toString())
|
||||
|
||||
// Should Correctly Serialize and Deserialize a Binary object
|
||||
var bin = new Binary()
|
||||
var string = 'binstring'
|
||||
for(var index = 0; index < string.length; index++) {
|
||||
bin.put(string.charAt(index))
|
||||
}
|
||||
var doc = {doc: bin}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
var deserialized_data = bsonC.deserialize(serialized_data);
|
||||
assert.equal(doc.doc.value(), deserialized_data.doc.value())
|
||||
|
||||
// Should Correctly Serialize and Deserialize a big Binary object
|
||||
var data = fs.readFileSync("../../test/gridstore/test_gs_weird_bug.png", 'binary');
|
||||
var bin = new Binary()
|
||||
bin.write(data)
|
||||
var doc = {doc: bin}
|
||||
var serialized_data = bsonC.serialize(doc)
|
||||
var deserialized_data = bsonC.deserialize(serialized_data);
|
||||
assert.equal(doc.doc.value(), deserialized_data.doc.value())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
132
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js
generated
vendored
Normal file
132
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/test/test_stackless_bson.js
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
var Buffer = require('buffer').Buffer,
|
||||
BSON = require('../bson').BSON,
|
||||
Buffer = require('buffer').Buffer,
|
||||
BSONJS = require('../../../lib/mongodb/bson/bson').BSON,
|
||||
BinaryParser = require('../../../lib/mongodb/bson/binary_parser').BinaryParser,
|
||||
Long = require('../../../lib/mongodb/bson/long').Long,
|
||||
ObjectID = require('../../../lib/mongodb/bson/bson').ObjectID,
|
||||
Binary = require('../../../lib/mongodb/bson/bson').Binary,
|
||||
Code = require('../../../lib/mongodb/bson/bson').Code,
|
||||
DBRef = require('../../../lib/mongodb/bson/bson').DBRef,
|
||||
Symbol = require('../../../lib/mongodb/bson/bson').Symbol,
|
||||
Double = require('../../../lib/mongodb/bson/bson').Double,
|
||||
MaxKey = require('../../../lib/mongodb/bson/bson').MaxKey,
|
||||
MinKey = require('../../../lib/mongodb/bson/bson').MinKey,
|
||||
Timestamp = require('../../../lib/mongodb/bson/bson').Timestamp;
|
||||
assert = require('assert');
|
||||
|
||||
if(process.env['npm_package_config_native'] != null) return;
|
||||
|
||||
console.log("=== EXECUTING TEST_STACKLESS_BSON ===");
|
||||
|
||||
// Parsers
|
||||
var bsonC = new BSON([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
var bsonJS = new BSONJS([Long, ObjectID, Binary, Code, DBRef, Symbol, Double, Timestamp, MaxKey, MinKey]);
|
||||
|
||||
// Number of iterations for the benchmark
|
||||
var COUNT = 10000;
|
||||
// var COUNT = 1;
|
||||
// Sample simple doc
|
||||
var doc = {key:"Hello world", key2:"šđžčćŠĐŽČĆ", key3:'客家话', key4:'how are you doing dog!!'};
|
||||
// var doc = {};
|
||||
// for(var i = 0; i < 100; i++) {
|
||||
// doc['string' + i] = "dumdyms fsdfdsfdsfdsfsdfdsfsdfsdfsdfsdfsdfsdfsdffsfsdfs";
|
||||
// }
|
||||
|
||||
// // Calculate size
|
||||
console.log(bsonC.calculateObjectSize2(doc));
|
||||
console.log(bsonJS.calculateObjectSize(doc));
|
||||
// assert.equal(bsonJS.calculateObjectSize(doc), bsonC.calculateObjectSize2(doc));
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
// Benchmark calculateObjectSize
|
||||
// ----------------------------------------------------------------------------
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// Benchmark 1 JS BSON
|
||||
console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize(object))")
|
||||
start = new Date
|
||||
|
||||
for (j=COUNT; --j>=0; ) {
|
||||
var objectBSON = bsonJS.calculateObjectSize(doc);
|
||||
}
|
||||
|
||||
end = new Date
|
||||
var opsprsecond = COUNT / ((end - start)/1000);
|
||||
console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
|
||||
// Benchmark 2 C++ BSON calculateObjectSize
|
||||
console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize(object))")
|
||||
start = new Date
|
||||
|
||||
for (j=COUNT; --j>=0; ) {
|
||||
var objectBSON = bsonC.calculateObjectSize(doc);
|
||||
}
|
||||
|
||||
end = new Date
|
||||
var opsprsecond = COUNT / ((end - start)/1000);
|
||||
console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
|
||||
// Benchmark 3 C++ BSON calculateObjectSize2
|
||||
console.log(COUNT + "x (objectBSON = bsonC.calculateObjectSize2(object))")
|
||||
start = new Date
|
||||
|
||||
for (j=COUNT; --j>=0; ) {
|
||||
var objectBSON = bsonC.calculateObjectSize2(doc);
|
||||
}
|
||||
|
||||
end = new Date
|
||||
var opsprsecond = COUNT / ((end - start)/1000);
|
||||
console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
|
||||
// // Serialize the content
|
||||
// var _serializedDoc1 = bsonJS.serialize(doc, true, false);
|
||||
// var _serializedDoc2 = bsonC.serialize2(doc, true, false);
|
||||
// console.dir(_serializedDoc1);
|
||||
// console.dir(_serializedDoc2);
|
||||
// assert.equal(_serializedDoc1.toString('base64'), _serializedDoc2.toString('base64'))
|
||||
//
|
||||
//
|
||||
// // Benchmark 1
|
||||
// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
|
||||
// start = new Date
|
||||
//
|
||||
// for (j=COUNT; --j>=0; ) {
|
||||
// // var objectBSON = bsonC.serialize2(doc, true, false);
|
||||
// var objectBSON = bsonJS.serialize(doc, true, false);
|
||||
// }
|
||||
//
|
||||
// end = new Date
|
||||
// var opsprsecond = COUNT / ((end - start)/1000);
|
||||
// console.log("bson size (bytes): ", objectbsonC.length);
|
||||
// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
|
||||
//
|
||||
// // Benchmark 2
|
||||
// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
|
||||
// start = new Date
|
||||
//
|
||||
// for (j=COUNT; --j>=0; ) {
|
||||
// var objectBSON = bsonC.serialize2(doc, true, false);
|
||||
// }
|
||||
//
|
||||
// end = new Date
|
||||
// var opsprsecond = COUNT / ((end - start)/1000);
|
||||
// console.log("bson size (bytes): ", objectbsonC.length);
|
||||
// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
|
||||
//
|
||||
// // Benchmark 3
|
||||
// console.log(COUNT + "x (objectBSON = bsonC.serialize(object))")
|
||||
// start = new Date
|
||||
//
|
||||
// for (j=COUNT; --j>=0; ) {
|
||||
// var objectBSON = bsonC.serialize(doc, true, false);
|
||||
// }
|
||||
//
|
||||
// end = new Date
|
||||
// var opsprsecond = COUNT / ((end - start)/1000);
|
||||
// console.log("bson size (bytes): ", objectbsonC.length);
|
||||
// console.log("time = ", end - start, "ms -", COUNT / ((end - start)/1000), " ops/sec");
|
||||
// console.log("MB/s = " + ((opsprsecond*objectbsonC.length)/1024));
|
||||
39
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/wscript
generated
vendored
Normal file
39
app/node_modules/mongoskin/node_modules/mongodb/external-libs/bson/wscript
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
import Options
|
||||
from os import unlink, symlink, popen
|
||||
from os.path import exists
|
||||
|
||||
srcdir = "."
|
||||
blddir = "build"
|
||||
VERSION = "0.1.0"
|
||||
|
||||
def set_options(opt):
|
||||
opt.tool_options("compiler_cxx")
|
||||
opt.add_option( '--debug'
|
||||
, action='store_true'
|
||||
, default=False
|
||||
, help='Build debug variant [Default: False]'
|
||||
, dest='debug'
|
||||
)
|
||||
|
||||
def configure(conf):
|
||||
conf.check_tool("compiler_cxx")
|
||||
conf.check_tool("node_addon")
|
||||
conf.env.append_value('CXXFLAGS', ['-O3', '-funroll-loops'])
|
||||
|
||||
# conf.env.append_value('CXXFLAGS', ['-DDEBUG', '-g', '-O0', '-Wall', '-Wextra'])
|
||||
# conf.check(lib='node', libpath=['/usr/lib', '/usr/local/lib'], uselib_store='NODE')
|
||||
|
||||
def build(bld):
|
||||
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
|
||||
obj.target = "bson"
|
||||
obj.source = ["bson.cc"]
|
||||
# obj.uselib = "NODE"
|
||||
|
||||
def shutdown():
|
||||
# HACK to get compress.node out of build directory.
|
||||
# better way to do this?
|
||||
if Options.commands['clean']:
|
||||
if exists('bson.node'): unlink('bson.node')
|
||||
else:
|
||||
if exists('build/default/bson.node') and not exists('bson.node'):
|
||||
symlink('build/default/bson.node', 'bson.node')
|
||||
1
app/node_modules/mongoskin/node_modules/mongodb/index.js
generated
vendored
Normal file
1
app/node_modules/mongoskin/node_modules/mongodb/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./lib/mongodb');
|
||||
40
app/node_modules/mongoskin/node_modules/mongodb/install.js
generated
vendored
Normal file
40
app/node_modules/mongoskin/node_modules/mongodb/install.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
var spawn = require('child_process').spawn,
|
||||
exec = require('child_process').exec;
|
||||
|
||||
process.stdout.write("================================================================================\n");
|
||||
process.stdout.write("= =\n");
|
||||
process.stdout.write("= To install with C++ bson parser do <npm install mongodb --mongodb:native> =\n");
|
||||
process.stdout.write("= =\n");
|
||||
process.stdout.write("================================================================================\n");
|
||||
|
||||
// Check if we want to build the native code
|
||||
var build_native = process.env['npm_package_config_native'] != null ? process.env['npm_package_config_native'] : 'false';
|
||||
build_native = build_native == 'true' ? true : false;
|
||||
// If we are building the native bson extension ensure we use gmake if available
|
||||
if(build_native) {
|
||||
// Check if we need to use gmake
|
||||
exec('which gmake', function(err, stdout, stderr) {
|
||||
// Set up spawn command
|
||||
var make = null;
|
||||
// No gmake build using make
|
||||
if(err != null) {
|
||||
make = spawn('make', ['total']);
|
||||
} else {
|
||||
make = spawn('gmake', ['total']);
|
||||
}
|
||||
|
||||
// Execute spawn
|
||||
make.stdout.on('data', function(data) {
|
||||
process.stdout.write(data);
|
||||
})
|
||||
|
||||
make.stderr.on('data', function(data) {
|
||||
process.stdout.write(data);
|
||||
})
|
||||
|
||||
make.on('exit', function(code) {
|
||||
process.stdout.write('child process exited with code ' + code + "\n");
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
390
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/admin.js
generated
vendored
Normal file
390
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/admin.js
generated
vendored
Normal file
@@ -0,0 +1,390 @@
|
||||
/*!
|
||||
* Module dependencies.
|
||||
*/
|
||||
var Collection = require('./collection').Collection,
|
||||
Cursor = require('./cursor').Cursor,
|
||||
DbCommand = require('./commands/db_command').DbCommand;
|
||||
|
||||
/**
|
||||
* Allows the user to access the admin functionality of MongoDB
|
||||
*
|
||||
* @class Represents the Admin methods of MongoDB.
|
||||
* @param {Object} db Current db instance we wish to perform Admin operations on.
|
||||
* @return {Function} Constructor for Admin type.
|
||||
*/
|
||||
function Admin(db) {
|
||||
if(!(this instanceof Admin)) return new Admin(db);
|
||||
|
||||
this.db = db;
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the server information for the current
|
||||
* instance of the db client
|
||||
*
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.buildInfo = function(callback) {
|
||||
this.serverInfo(callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the server information for the current
|
||||
* instance of the db client
|
||||
*
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api private
|
||||
*/
|
||||
Admin.prototype.serverInfo = function(callback) {
|
||||
var self = this;
|
||||
var command = {buildinfo:1};
|
||||
this.command(command, function(err, doc) {
|
||||
if(err != null) return callback(err, null);
|
||||
return callback(null, doc.documents[0]);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve this db's server status.
|
||||
*
|
||||
* @param {Function} callback returns the server status.
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.serverStatus = function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.command({serverStatus: 1}, function(err, result) {
|
||||
if (err == null && result.documents[0].ok == 1) {
|
||||
callback(null, result.documents[0]);
|
||||
} else {
|
||||
if (err) {
|
||||
callback(err, false);
|
||||
} else {
|
||||
callback(self.wrap(result.documents[0]), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieve the current profiling Level for MongoDB
|
||||
*
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.profilingLevel = function(callback) {
|
||||
var self = this;
|
||||
var command = {profile:-1};
|
||||
|
||||
this.command(command, function(err, doc) {
|
||||
doc = doc.documents[0];
|
||||
|
||||
if(err == null && (doc.ok == 1 || typeof doc.was === 'number')) {
|
||||
var was = doc.was;
|
||||
if(was == 0) {
|
||||
callback(null, "off");
|
||||
} else if(was == 1) {
|
||||
callback(null, "slow_only");
|
||||
} else if(was == 2) {
|
||||
callback(null, "all");
|
||||
} else {
|
||||
callback(new Error("Error: illegal profiling level value " + was), null);
|
||||
}
|
||||
} else {
|
||||
err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Ping the MongoDB server and retrieve results
|
||||
*
|
||||
* @param {Object} [options] Optional parameters to the command.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.ping = function(options, callback) {
|
||||
// Unpack calls
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
callback = args.pop();
|
||||
options = args.length ? args.shift() : {};
|
||||
// Set self
|
||||
var self = this;
|
||||
var databaseName = this.db.databaseName;
|
||||
this.db.databaseName = 'admin';
|
||||
this.db.executeDbCommand({ping:1}, options, function(err, result) {
|
||||
self.db.databaseName = databaseName;
|
||||
return callback(err, result);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticate against MongoDB
|
||||
*
|
||||
* @param {String} username The user name for the authentication.
|
||||
* @param {String} password The password for the authentication.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
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);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Logout current authenticated user
|
||||
*
|
||||
* @param {Object} [options] Optional parameters to the command.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.logout = function(callback) {
|
||||
var self = this;
|
||||
var databaseName = this.db.databaseName;
|
||||
this.db.databaseName = 'admin';
|
||||
this.db.logout(function(err, result) {
|
||||
return callback(err, result);
|
||||
})
|
||||
|
||||
self.db.databaseName = databaseName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a user to the MongoDB server, if the user exists it will
|
||||
* overwrite the current password
|
||||
*
|
||||
* Options
|
||||
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
|
||||
*
|
||||
* @param {String} username The user name for the authentication.
|
||||
* @param {String} password The password for the authentication.
|
||||
* @param {Object} [options] additional options during update.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.addUser = function(username, password, options, callback) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 2);
|
||||
callback = args.pop();
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
var self = this;
|
||||
var databaseName = this.db.databaseName;
|
||||
this.db.databaseName = 'admin';
|
||||
this.db.addUser(username, password, options, function(err, result) {
|
||||
self.db.databaseName = databaseName;
|
||||
return callback(err, result);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a user from the MongoDB server
|
||||
*
|
||||
* Options
|
||||
* - **safe** {true | {w:n, wtimeout:n} | {fsync:true}, default:false}, executes with a getLastError command returning the results of the command on MongoDB.
|
||||
*
|
||||
* @param {String} username The user name for the authentication.
|
||||
* @param {Object} [options] additional options during update.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.removeUser = function(username, options, callback) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
callback = args.pop();
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
var self = this;
|
||||
var databaseName = this.db.databaseName;
|
||||
this.db.databaseName = 'admin';
|
||||
this.db.removeUser(username, options, function(err, result) {
|
||||
self.db.databaseName = databaseName;
|
||||
return callback(err, result);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the current profiling level of MongoDB
|
||||
*
|
||||
* @param {String} level The new profiling level (off, slow_only, all)
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.setProfilingLevel = function(level, callback) {
|
||||
var self = this;
|
||||
var command = {};
|
||||
var profile = 0;
|
||||
|
||||
if(level == "off") {
|
||||
profile = 0;
|
||||
} else if(level == "slow_only") {
|
||||
profile = 1;
|
||||
} else if(level == "all") {
|
||||
profile = 2;
|
||||
} else {
|
||||
return callback(new Error("Error: illegal profiling level value " + level));
|
||||
}
|
||||
|
||||
// Set up the profile number
|
||||
command['profile'] = profile;
|
||||
// Execute the command to set the profiling level
|
||||
this.command(command, function(err, doc) {
|
||||
doc = doc.documents[0];
|
||||
|
||||
if(err == null && (doc.ok == 1 || typeof doc.was === 'number')) {
|
||||
return callback(null, level);
|
||||
} else {
|
||||
return err != null ? callback(err, null) : callback(new Error("Error with profile command"), null);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrive the current profiling information for MongoDB
|
||||
*
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.profilingInfo = function(callback) {
|
||||
var self = this;
|
||||
var databaseName = this.db.databaseName;
|
||||
this.db.databaseName = 'admin';
|
||||
|
||||
try {
|
||||
new Cursor(this.db, new Collection(this.db, DbCommand.SYSTEM_PROFILE_COLLECTION), {}).toArray(function(err, items) {
|
||||
return callback(err, items);
|
||||
});
|
||||
} catch (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
self.db.databaseName = databaseName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Execute a db command against the Admin database
|
||||
*
|
||||
* @param {Object} command A command object `{ping:1}`.
|
||||
* @param {Object} [options] Optional parameters to the command.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.command = function(command, options, callback) {
|
||||
var self = this;
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
callback = args.pop();
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
// Execute a command
|
||||
this.db.executeDbAdminCommand(command, options, function(err, result) {
|
||||
// Ensure change before event loop executes
|
||||
return callback != null ? callback(err, result) : null;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an existing collection
|
||||
*
|
||||
* @param {String} collectionName The name of the collection to validate.
|
||||
* @param {Object} [options] Optional parameters to the command.
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.validateCollection = function(collectionName, options, callback) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
callback = args.pop();
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
var self = this;
|
||||
var command = {validate: collectionName};
|
||||
var keys = Object.keys(options);
|
||||
|
||||
// Decorate command with extra options
|
||||
for(var i = 0; i < keys.length; i++) {
|
||||
if(options.hasOwnProperty(keys[i])) {
|
||||
command[keys[i]] = options[keys[i]];
|
||||
}
|
||||
}
|
||||
|
||||
this.db.executeDbCommand(command, function(err, doc) {
|
||||
if(err != null) return callback(err, null);
|
||||
doc = doc.documents[0];
|
||||
|
||||
if(doc.ok == 0) {
|
||||
return callback(new Error("Error with validate command"), null);
|
||||
} else if(doc.result != null && doc.result.constructor != String) {
|
||||
return callback(new Error("Error with validation data"), null);
|
||||
} else if(doc.result != null && doc.result.match(/exception|corrupt/) != null) {
|
||||
return callback(new Error("Error: invalid collection " + collectionName), null);
|
||||
} else if(doc.valid != null && !doc.valid) {
|
||||
return callback(new Error("Error: invalid collection " + collectionName), null);
|
||||
} else {
|
||||
return callback(null, doc);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* List the available databases
|
||||
*
|
||||
* @param {Function} callback Callback function of format `function(err, result) {}`.
|
||||
* @return {null} Returns no result
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.listDatabases = function(callback) {
|
||||
// Execute the listAllDatabases command
|
||||
this.db.executeDbAdminCommand({listDatabases:1}, {}, function(err, result) {
|
||||
if(err != null) {
|
||||
callback(err, null);
|
||||
} else {
|
||||
callback(null, result.documents[0]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get ReplicaSet status
|
||||
*
|
||||
* @param {Function} callback returns the replica set status (if available).
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Admin.prototype.replSetGetStatus = function(callback) {
|
||||
var self = this;
|
||||
|
||||
this.command({replSetGetStatus:1}, function(err, result) {
|
||||
if (err == null && result.documents[0].ok == 1) {
|
||||
callback(null, result.documents[0]);
|
||||
} else {
|
||||
if (err) {
|
||||
callback(err, false);
|
||||
} else {
|
||||
callback(self.db.wrap(result.documents[0]), false);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
exports.Admin = Admin;
|
||||
1517
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/collection.js
generated
vendored
Normal file
1517
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/collection.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
27
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/base_command.js
generated
vendored
Normal file
27
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/base_command.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
Base object used for common functionality
|
||||
**/
|
||||
var BaseCommand = exports.BaseCommand = function() {
|
||||
};
|
||||
|
||||
var id = 1;
|
||||
BaseCommand.prototype.getRequestId = function() {
|
||||
if (!this.requestId) this.requestId = id++;
|
||||
return this.requestId;
|
||||
};
|
||||
|
||||
BaseCommand.prototype.updateRequestId = function() {
|
||||
this.requestId = id++;
|
||||
return this.requestId;
|
||||
};
|
||||
|
||||
// OpCodes
|
||||
BaseCommand.OP_REPLY = 1;
|
||||
BaseCommand.OP_MSG = 1000;
|
||||
BaseCommand.OP_UPDATE = 2001;
|
||||
BaseCommand.OP_INSERT = 2002;
|
||||
BaseCommand.OP_GET_BY_OID = 2003;
|
||||
BaseCommand.OP_QUERY = 2004;
|
||||
BaseCommand.OP_GET_MORE = 2005;
|
||||
BaseCommand.OP_DELETE = 2006;
|
||||
BaseCommand.OP_KILL_CURSORS = 2007;
|
||||
207
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/db_command.js
generated
vendored
Normal file
207
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/db_command.js
generated
vendored
Normal file
@@ -0,0 +1,207 @@
|
||||
var QueryCommand = require('./query_command').QueryCommand,
|
||||
InsertCommand = require('./insert_command').InsertCommand,
|
||||
inherits = require('util').inherits,
|
||||
crypto = require('crypto');
|
||||
|
||||
/**
|
||||
Db Command
|
||||
**/
|
||||
var DbCommand = exports.DbCommand = function(dbInstance, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
|
||||
QueryCommand.call(this);
|
||||
this.collectionName = collectionName;
|
||||
this.queryOptions = queryOptions;
|
||||
this.numberToSkip = numberToSkip;
|
||||
this.numberToReturn = numberToReturn;
|
||||
this.query = query;
|
||||
this.returnFieldSelector = returnFieldSelector;
|
||||
this.db = dbInstance;
|
||||
|
||||
// Make sure we don't get a null exception
|
||||
options = options == null ? {} : options;
|
||||
// Let us defined on a command basis if we want functions to be serialized or not
|
||||
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
|
||||
this.serializeFunctions = true;
|
||||
}
|
||||
};
|
||||
|
||||
inherits(DbCommand, QueryCommand);
|
||||
|
||||
// Constants
|
||||
DbCommand.SYSTEM_NAMESPACE_COLLECTION = "system.namespaces";
|
||||
DbCommand.SYSTEM_INDEX_COLLECTION = "system.indexes";
|
||||
DbCommand.SYSTEM_PROFILE_COLLECTION = "system.profile";
|
||||
DbCommand.SYSTEM_USER_COLLECTION = "system.users";
|
||||
DbCommand.SYSTEM_COMMAND_COLLECTION = "$cmd";
|
||||
|
||||
// New commands
|
||||
DbCommand.NcreateIsMasterCommand = function(db, databaseName) {
|
||||
return new DbCommand(db, databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
|
||||
};
|
||||
|
||||
// Provide constructors for different db commands
|
||||
DbCommand.createIsMasterCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'ismaster':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createCollectionInfoCommand = function(db, selector) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_NAMESPACE_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, 0, selector, null);
|
||||
};
|
||||
|
||||
DbCommand.createGetNonceCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getnonce':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createAuthenticationCommand = function(db, username, password, nonce) {
|
||||
// Use node md5 generator
|
||||
var md5 = crypto.createHash('md5');
|
||||
// Generate keys used for authentication
|
||||
md5.update(username + ":mongo:" + password);
|
||||
var hash_password = md5.digest('hex');
|
||||
// Final key
|
||||
md5 = crypto.createHash('md5');
|
||||
md5.update(nonce + username + hash_password);
|
||||
var key = md5.digest('hex');
|
||||
// Creat selector
|
||||
var selector = {'authenticate':1, 'user':username, 'nonce':nonce, 'key':key};
|
||||
// Create db command
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NONE, 0, -1, selector, null);
|
||||
};
|
||||
|
||||
DbCommand.createLogoutCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'logout':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createCreateCollectionCommand = function(db, collectionName, options) {
|
||||
var selector = {'create':collectionName};
|
||||
// Modify the options to ensure correct behaviour
|
||||
for(var name in options) {
|
||||
if(options[name] != null && options[name].constructor != Function) selector[name] = options[name];
|
||||
}
|
||||
// Execute the command
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, selector, null);
|
||||
};
|
||||
|
||||
DbCommand.createDropCollectionCommand = function(db, collectionName) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'drop':collectionName}, null);
|
||||
};
|
||||
|
||||
DbCommand.createRenameCollectionCommand = function(db, fromCollectionName, toCollectionName) {
|
||||
var renameCollection = db.databaseName + "." + fromCollectionName;
|
||||
var toCollection = db.databaseName + "." + toCollectionName;
|
||||
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'renameCollection':renameCollection, 'to':toCollection}, null);
|
||||
};
|
||||
|
||||
DbCommand.createGetLastErrorCommand = function(options, db) {
|
||||
|
||||
if (typeof db === 'undefined') {
|
||||
db = options;
|
||||
options = {};
|
||||
}
|
||||
// Final command
|
||||
var command = {'getlasterror':1};
|
||||
// If we have an options Object let's merge in the fields (fsync/wtimeout/w)
|
||||
if('object' === typeof options) {
|
||||
for(var name in options) {
|
||||
command[name] = options[name]
|
||||
}
|
||||
}
|
||||
|
||||
// Execute command
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command, null);
|
||||
};
|
||||
|
||||
DbCommand.createGetLastStatusCommand = DbCommand.createGetLastErrorCommand;
|
||||
|
||||
DbCommand.createGetPreviousErrorsCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'getpreverror':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createResetErrorHistoryCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reseterror':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createCreateIndexCommand = function(db, collectionName, fieldOrSpec, options) {
|
||||
var fieldHash = {};
|
||||
var indexes = [];
|
||||
var keys;
|
||||
|
||||
// Get all the fields accordingly
|
||||
if (fieldOrSpec.constructor === String) { // 'type'
|
||||
indexes.push(fieldOrSpec + '_' + 1);
|
||||
fieldHash[fieldOrSpec] = 1;
|
||||
} else if (fieldOrSpec.constructor === Array) { // [{location:'2d'}, ...]
|
||||
fieldOrSpec.forEach(function(f) {
|
||||
if (f.constructor === String) { // [{location:'2d'}, 'type']
|
||||
indexes.push(f + '_' + 1);
|
||||
fieldHash[f] = 1;
|
||||
} else if (f.constructor === Array) { // [['location', '2d'],['type', 1]]
|
||||
indexes.push(f[0] + '_' + (f[1] || 1));
|
||||
fieldHash[f[0]] = f[1] || 1;
|
||||
} else if (f.constructor === Object) { // [{location:'2d'}, {type:1}]
|
||||
keys = Object.keys(f);
|
||||
keys.forEach(function(k) {
|
||||
indexes.push(k + '_' + f[k]);
|
||||
fieldHash[k] = f[k];
|
||||
});
|
||||
} else {
|
||||
// undefined
|
||||
}
|
||||
});
|
||||
} else if (fieldOrSpec.constructor === Object) { // {location:'2d', type:1}
|
||||
keys = Object.keys(fieldOrSpec);
|
||||
keys.forEach(function(key) {
|
||||
indexes.push(key + '_' + fieldOrSpec[key]);
|
||||
fieldHash[key] = fieldOrSpec[key];
|
||||
});
|
||||
}
|
||||
|
||||
// Generate the index name
|
||||
var indexName = indexes.join("_");
|
||||
// Build the selector
|
||||
var selector = {'ns':(db.databaseName + "." + collectionName), 'key':fieldHash, 'name':indexName};
|
||||
|
||||
// Ensure we have a correct finalUnique
|
||||
var finalUnique = options == null || 'object' === typeof options ? false : options;
|
||||
// Set up options
|
||||
options = options == null || typeof options == 'boolean' ? {} : options;
|
||||
|
||||
// Add all the options
|
||||
var keys = Object.keys(options);
|
||||
// Add all the fields to the selector
|
||||
for(var i = 0; i < keys.length; i++) {
|
||||
selector[keys[i]] = options[keys[i]];
|
||||
}
|
||||
|
||||
// If we don't have the unique property set on the selector
|
||||
if(selector['unique'] == null) selector['unique'] = finalUnique;
|
||||
// Create the insert command for the index and return the document
|
||||
return new InsertCommand(db, db.databaseName + "." + DbCommand.SYSTEM_INDEX_COLLECTION, false).add(selector);
|
||||
};
|
||||
|
||||
DbCommand.logoutCommand = function(db, command_hash) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
|
||||
}
|
||||
|
||||
DbCommand.createDropIndexCommand = function(db, collectionName, indexName) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'deleteIndexes':collectionName, 'index':indexName}, null);
|
||||
};
|
||||
|
||||
DbCommand.createReIndexCommand = function(db, collectionName) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'reIndex':collectionName}, null);
|
||||
};
|
||||
|
||||
DbCommand.createDropDatabaseCommand = function(db) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, {'dropDatabase':1}, null);
|
||||
};
|
||||
|
||||
DbCommand.createDbCommand = function(db, command_hash, options) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null, options);
|
||||
};
|
||||
|
||||
DbCommand.createAdminDbCommand = function(db, command_hash) {
|
||||
return new DbCommand(db, "admin." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT, 0, -1, command_hash, null);
|
||||
};
|
||||
|
||||
DbCommand.createDbSlaveOkCommand = function(db, command_hash, options) {
|
||||
return new DbCommand(db, db.databaseName + "." + DbCommand.SYSTEM_COMMAND_COLLECTION, QueryCommand.OPTS_NO_CURSOR_TIMEOUT | QueryCommand.OPTS_SLAVE, 0, -1, command_hash, null, options);
|
||||
};
|
||||
114
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/delete_command.js
generated
vendored
Normal file
114
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/delete_command.js
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits;
|
||||
|
||||
/**
|
||||
Insert Document Command
|
||||
**/
|
||||
var DeleteCommand = exports.DeleteCommand = function(db, collectionName, selector, flags) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
// Validate correctness off the selector
|
||||
var object = selector;
|
||||
if(Buffer.isBuffer(object)) {
|
||||
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) {
|
||||
var error = new Error("delete raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.flags = flags;
|
||||
this.collectionName = collectionName;
|
||||
this.selector = selector;
|
||||
this.db = db;
|
||||
};
|
||||
|
||||
inherits(DeleteCommand, BaseCommand);
|
||||
|
||||
DeleteCommand.OP_DELETE = 2006;
|
||||
|
||||
/*
|
||||
struct {
|
||||
MsgHeader header; // standard message header
|
||||
int32 ZERO; // 0 - reserved for future use
|
||||
cstring fullCollectionName; // "dbname.collectionname"
|
||||
int32 ZERO; // 0 - reserved for future use
|
||||
mongo.BSON selector; // query object. See below for details.
|
||||
}
|
||||
*/
|
||||
DeleteCommand.prototype.toBinary = function() {
|
||||
// Calculate total length of the document
|
||||
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.selector, false, true) + (4 * 4);
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index] = totalLengthOfCommand & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the request ID
|
||||
_command[_index + 3] = (this.requestId >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index] = this.requestId & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
// Write the op_code for the command
|
||||
_command[_index + 3] = (DeleteCommand.OP_DELETE >> 24) & 0xff;
|
||||
_command[_index + 2] = (DeleteCommand.OP_DELETE >> 16) & 0xff;
|
||||
_command[_index + 1] = (DeleteCommand.OP_DELETE >> 8) & 0xff;
|
||||
_command[_index] = DeleteCommand.OP_DELETE & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
|
||||
// Write the collection name to the command
|
||||
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Write the flags
|
||||
_command[_index + 3] = (this.flags >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.flags >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.flags >> 8) & 0xff;
|
||||
_command[_index] = this.flags & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
|
||||
// Serialize the selector
|
||||
// If we are passing a raw buffer, do minimal validation
|
||||
if(Buffer.isBuffer(this.selector)) {
|
||||
documentLength = this.selector.length;
|
||||
// Copy the data into the current buffer
|
||||
this.selector.copy(_command, _index);
|
||||
} else {
|
||||
documentLength = this.db.bson.serializeWithBufferAndIndex(this.selector, this.checkKeys, _command, _index) - _index + 1;
|
||||
}
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
return _command;
|
||||
};
|
||||
83
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/get_more_command.js
generated
vendored
Normal file
83
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/get_more_command.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits,
|
||||
binaryutils = require('../utils');
|
||||
|
||||
/**
|
||||
Get More Document Command
|
||||
**/
|
||||
var GetMoreCommand = exports.GetMoreCommand = function(db, collectionName, numberToReturn, cursorId) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
this.collectionName = collectionName;
|
||||
this.numberToReturn = numberToReturn;
|
||||
this.cursorId = cursorId;
|
||||
this.db = db;
|
||||
};
|
||||
|
||||
inherits(GetMoreCommand, BaseCommand);
|
||||
|
||||
GetMoreCommand.OP_GET_MORE = 2005;
|
||||
|
||||
GetMoreCommand.prototype.toBinary = function() {
|
||||
// Calculate total length of the document
|
||||
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 8 + (4 * 4);
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index++] = totalLengthOfCommand & 0xff;
|
||||
_command[_index++] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index++] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index++] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
|
||||
// Write the request ID
|
||||
_command[_index++] = this.requestId & 0xff;
|
||||
_command[_index++] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index++] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index++] = (this.requestId >> 24) & 0xff;
|
||||
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
|
||||
// Write the op_code for the command
|
||||
_command[_index++] = GetMoreCommand.OP_GET_MORE & 0xff;
|
||||
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 8) & 0xff;
|
||||
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 16) & 0xff;
|
||||
_command[_index++] = (GetMoreCommand.OP_GET_MORE >> 24) & 0xff;
|
||||
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
|
||||
// Write the collection name to the command
|
||||
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Number of documents to return
|
||||
_command[_index++] = this.numberToReturn & 0xff;
|
||||
_command[_index++] = (this.numberToReturn >> 8) & 0xff;
|
||||
_command[_index++] = (this.numberToReturn >> 16) & 0xff;
|
||||
_command[_index++] = (this.numberToReturn >> 24) & 0xff;
|
||||
|
||||
// Encode the cursor id
|
||||
var low_bits = this.cursorId.getLowBits();
|
||||
// Encode low bits
|
||||
_command[_index++] = low_bits & 0xff;
|
||||
_command[_index++] = (low_bits >> 8) & 0xff;
|
||||
_command[_index++] = (low_bits >> 16) & 0xff;
|
||||
_command[_index++] = (low_bits >> 24) & 0xff;
|
||||
|
||||
var high_bits = this.cursorId.getHighBits();
|
||||
// Encode high bits
|
||||
_command[_index++] = high_bits & 0xff;
|
||||
_command[_index++] = (high_bits >> 8) & 0xff;
|
||||
_command[_index++] = (high_bits >> 16) & 0xff;
|
||||
_command[_index++] = (high_bits >> 24) & 0xff;
|
||||
// Return command
|
||||
return _command;
|
||||
};
|
||||
141
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/insert_command.js
generated
vendored
Normal file
141
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/insert_command.js
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits;
|
||||
|
||||
/**
|
||||
Insert Document Command
|
||||
**/
|
||||
var InsertCommand = exports.InsertCommand = function(db, collectionName, checkKeys, options) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
this.collectionName = collectionName;
|
||||
this.documents = [];
|
||||
this.checkKeys = checkKeys == null ? true : checkKeys;
|
||||
this.db = db;
|
||||
this.flags = 0;
|
||||
this.serializeFunctions = false;
|
||||
|
||||
// Ensure valid options hash
|
||||
options = options == null ? {} : options;
|
||||
|
||||
// Check if we have keepGoing set -> set flag if it's the case
|
||||
if(options['keepGoing'] != null && options['keepGoing']) {
|
||||
// This will finish inserting all non-index violating documents even if it returns an error
|
||||
this.flags = 1;
|
||||
}
|
||||
|
||||
// Let us defined on a command basis if we want functions to be serialized or not
|
||||
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
|
||||
this.serializeFunctions = true;
|
||||
}
|
||||
};
|
||||
|
||||
inherits(InsertCommand, BaseCommand);
|
||||
|
||||
// OpCodes
|
||||
InsertCommand.OP_INSERT = 2002;
|
||||
|
||||
InsertCommand.prototype.add = function(document) {
|
||||
if(Buffer.isBuffer(document)) {
|
||||
var object_size = document[0] | document[1] << 8 | document[2] << 16 | document[3] << 24;
|
||||
if(object_size != document.length) {
|
||||
var error = new Error("insert raw message size does not match message header size [" + document.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.documents.push(document);
|
||||
return this;
|
||||
};
|
||||
|
||||
/*
|
||||
struct {
|
||||
MsgHeader header; // standard message header
|
||||
int32 ZERO; // 0 - reserved for future use
|
||||
cstring fullCollectionName; // "dbname.collectionname"
|
||||
BSON[] documents; // one or more documents to insert into the collection
|
||||
}
|
||||
*/
|
||||
InsertCommand.prototype.toBinary = function() {
|
||||
// Calculate total length of the document
|
||||
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + (4 * 4);
|
||||
// var docLength = 0
|
||||
for(var i = 0; i < this.documents.length; i++) {
|
||||
if(Buffer.isBuffer(this.documents[i])) {
|
||||
totalLengthOfCommand += this.documents[i].length;
|
||||
} else {
|
||||
// Calculate size of document
|
||||
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.documents[i], this.serializeFunctions, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index] = totalLengthOfCommand & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the request ID
|
||||
_command[_index + 3] = (this.requestId >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index] = this.requestId & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
// Write the op_code for the command
|
||||
_command[_index + 3] = (InsertCommand.OP_INSERT >> 24) & 0xff;
|
||||
_command[_index + 2] = (InsertCommand.OP_INSERT >> 16) & 0xff;
|
||||
_command[_index + 1] = (InsertCommand.OP_INSERT >> 8) & 0xff;
|
||||
_command[_index] = InsertCommand.OP_INSERT & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write flags if any
|
||||
_command[_index + 3] = (this.flags >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.flags >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.flags >> 8) & 0xff;
|
||||
_command[_index] = this.flags & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the collection name to the command
|
||||
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Write all the bson documents to the buffer at the index offset
|
||||
for(var i = 0; i < this.documents.length; i++) {
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
var object = this.documents[i];
|
||||
|
||||
// Serialize the selector
|
||||
// If we are passing a raw buffer, do minimal validation
|
||||
if(Buffer.isBuffer(object)) {
|
||||
documentLength = object.length;
|
||||
// Copy the data into the current buffer
|
||||
object.copy(_command, _index);
|
||||
} else {
|
||||
// Serialize the document straight to the buffer
|
||||
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
|
||||
}
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
}
|
||||
|
||||
return _command;
|
||||
};
|
||||
98
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js
generated
vendored
Normal file
98
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/kill_cursor_command.js
generated
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits,
|
||||
binaryutils = require('../utils');
|
||||
|
||||
/**
|
||||
Insert Document Command
|
||||
**/
|
||||
var KillCursorCommand = exports.KillCursorCommand = function(db, cursorIds) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
this.cursorIds = cursorIds;
|
||||
this.db = db;
|
||||
};
|
||||
|
||||
inherits(KillCursorCommand, BaseCommand);
|
||||
|
||||
KillCursorCommand.OP_KILL_CURSORS = 2007;
|
||||
|
||||
/*
|
||||
struct {
|
||||
MsgHeader header; // standard message header
|
||||
int32 ZERO; // 0 - reserved for future use
|
||||
int32 numberOfCursorIDs; // number of cursorIDs in message
|
||||
int64[] cursorIDs; // array of cursorIDs to close
|
||||
}
|
||||
*/
|
||||
KillCursorCommand.prototype.toBinary = function() {
|
||||
// Calculate total length of the document
|
||||
var totalLengthOfCommand = 4 + 4 + (4 * 4) + (this.cursorIds.length * 8);
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index] = totalLengthOfCommand & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the request ID
|
||||
_command[_index + 3] = (this.requestId >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index] = this.requestId & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
// Write the op_code for the command
|
||||
_command[_index + 3] = (KillCursorCommand.OP_KILL_CURSORS >> 24) & 0xff;
|
||||
_command[_index + 2] = (KillCursorCommand.OP_KILL_CURSORS >> 16) & 0xff;
|
||||
_command[_index + 1] = (KillCursorCommand.OP_KILL_CURSORS >> 8) & 0xff;
|
||||
_command[_index] = KillCursorCommand.OP_KILL_CURSORS & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
|
||||
// Number of cursors to kill
|
||||
var numberOfCursors = this.cursorIds.length;
|
||||
_command[_index + 3] = (numberOfCursors >> 24) & 0xff;
|
||||
_command[_index + 2] = (numberOfCursors >> 16) & 0xff;
|
||||
_command[_index + 1] = (numberOfCursors >> 8) & 0xff;
|
||||
_command[_index] = numberOfCursors & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Encode all the cursors
|
||||
for(var i = 0; i < this.cursorIds.length; i++) {
|
||||
// Encode the cursor id
|
||||
var low_bits = this.cursorIds[i].getLowBits();
|
||||
// Encode low bits
|
||||
_command[_index + 3] = (low_bits >> 24) & 0xff;
|
||||
_command[_index + 2] = (low_bits >> 16) & 0xff;
|
||||
_command[_index + 1] = (low_bits >> 8) & 0xff;
|
||||
_command[_index] = low_bits & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
var high_bits = this.cursorIds[i].getHighBits();
|
||||
// Encode high bits
|
||||
_command[_index + 3] = (high_bits >> 24) & 0xff;
|
||||
_command[_index + 2] = (high_bits >> 16) & 0xff;
|
||||
_command[_index + 1] = (high_bits >> 8) & 0xff;
|
||||
_command[_index] = high_bits & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
}
|
||||
|
||||
return _command;
|
||||
};
|
||||
210
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/query_command.js
generated
vendored
Normal file
210
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/query_command.js
generated
vendored
Normal file
@@ -0,0 +1,210 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits;
|
||||
|
||||
/**
|
||||
Insert Document Command
|
||||
**/
|
||||
var QueryCommand = exports.QueryCommand = function(db, collectionName, queryOptions, numberToSkip, numberToReturn, query, returnFieldSelector, options) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
// Validate correctness off the selector
|
||||
var object = query,
|
||||
object_size;
|
||||
if(Buffer.isBuffer(object)) {
|
||||
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) {
|
||||
var error = new Error("query selector raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
object = returnFieldSelector;
|
||||
if(Buffer.isBuffer(object)) {
|
||||
object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) {
|
||||
var error = new Error("query fields raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we don't get a null exception
|
||||
options = options == null ? {} : options;
|
||||
// Set up options
|
||||
this.collectionName = collectionName;
|
||||
this.queryOptions = queryOptions;
|
||||
this.numberToSkip = numberToSkip;
|
||||
this.numberToReturn = numberToReturn;
|
||||
this.query = query;
|
||||
this.returnFieldSelector = returnFieldSelector;
|
||||
this.db = db;
|
||||
|
||||
// Let us defined on a command basis if we want functions to be serialized or not
|
||||
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
|
||||
this.serializeFunctions = true;
|
||||
}
|
||||
};
|
||||
|
||||
inherits(QueryCommand, BaseCommand);
|
||||
|
||||
QueryCommand.OP_QUERY = 2004;
|
||||
|
||||
/*
|
||||
struct {
|
||||
MsgHeader header; // standard message header
|
||||
int32 opts; // query options. See below for details.
|
||||
cstring fullCollectionName; // "dbname.collectionname"
|
||||
int32 numberToSkip; // number of documents to skip when returning results
|
||||
int32 numberToReturn; // number of documents to return in the first OP_REPLY
|
||||
BSON query ; // query object. See below for details.
|
||||
[ BSON returnFieldSelector; ] // OPTIONAL : selector indicating the fields to return. See below for details.
|
||||
}
|
||||
*/
|
||||
QueryCommand.prototype.toBinary = function() {
|
||||
var totalLengthOfCommand = 0;
|
||||
// Calculate total length of the document
|
||||
if(Buffer.isBuffer(this.query)) {
|
||||
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.query.length + (4 * 4);
|
||||
} else {
|
||||
totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + 4 + this.db.bson.calculateObjectSize(this.query, this.serializeFunctions, true) + (4 * 4);
|
||||
}
|
||||
|
||||
// Calculate extra fields size
|
||||
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
|
||||
if(Object.keys(this.returnFieldSelector).length > 0) {
|
||||
totalLengthOfCommand += this.db.bson.calculateObjectSize(this.returnFieldSelector, this.serializeFunctions, true);
|
||||
}
|
||||
} else if(Buffer.isBuffer(this.returnFieldSelector)) {
|
||||
totalLengthOfCommand += this.returnFieldSelector.length;
|
||||
}
|
||||
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index] = totalLengthOfCommand & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the request ID
|
||||
_command[_index + 3] = (this.requestId >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index] = this.requestId & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
// Write the op_code for the command
|
||||
_command[_index + 3] = (QueryCommand.OP_QUERY >> 24) & 0xff;
|
||||
_command[_index + 2] = (QueryCommand.OP_QUERY >> 16) & 0xff;
|
||||
_command[_index + 1] = (QueryCommand.OP_QUERY >> 8) & 0xff;
|
||||
_command[_index] = QueryCommand.OP_QUERY & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write the query options
|
||||
_command[_index + 3] = (this.queryOptions >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.queryOptions >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.queryOptions >> 8) & 0xff;
|
||||
_command[_index] = this.queryOptions & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write the collection name to the command
|
||||
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Write the number of documents to skip
|
||||
_command[_index + 3] = (this.numberToSkip >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.numberToSkip >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.numberToSkip >> 8) & 0xff;
|
||||
_command[_index] = this.numberToSkip & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write the number of documents to return
|
||||
_command[_index + 3] = (this.numberToReturn >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.numberToReturn >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.numberToReturn >> 8) & 0xff;
|
||||
_command[_index] = this.numberToReturn & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
var object = this.query;
|
||||
|
||||
// Serialize the selector
|
||||
if(Buffer.isBuffer(object)) {
|
||||
documentLength = object.length;
|
||||
// Copy the data into the current buffer
|
||||
object.copy(_command, _index);
|
||||
} else {
|
||||
// Serialize the document straight to the buffer
|
||||
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
|
||||
}
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Push field selector if available
|
||||
if(this.returnFieldSelector != null && !(Buffer.isBuffer(this.returnFieldSelector))) {
|
||||
if(Object.keys(this.returnFieldSelector).length > 0) {
|
||||
var documentLength = this.db.bson.serializeWithBufferAndIndex(this.returnFieldSelector, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
}
|
||||
} if(this.returnFieldSelector != null && Buffer.isBuffer(this.returnFieldSelector)) {
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
var object = this.returnFieldSelector;
|
||||
|
||||
// Serialize the selector
|
||||
documentLength = object.length;
|
||||
// Copy the data into the current buffer
|
||||
object.copy(_command, _index);
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
}
|
||||
|
||||
// Return finished command
|
||||
return _command;
|
||||
};
|
||||
|
||||
// Constants
|
||||
QueryCommand.OPTS_NONE = 0;
|
||||
QueryCommand.OPTS_TAILABLE_CURSOR = 2;
|
||||
QueryCommand.OPTS_SLAVE = 4;
|
||||
QueryCommand.OPTS_OPLOG_REPLY = 8;
|
||||
QueryCommand.OPTS_NO_CURSOR_TIMEOUT = 16;
|
||||
QueryCommand.OPTS_AWAIT_DATA = 32;
|
||||
QueryCommand.OPTS_EXHAUST = 64;
|
||||
174
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/update_command.js
generated
vendored
Normal file
174
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/commands/update_command.js
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
var BaseCommand = require('./base_command').BaseCommand,
|
||||
inherits = require('util').inherits;
|
||||
|
||||
/**
|
||||
Update Document Command
|
||||
**/
|
||||
var UpdateCommand = exports.UpdateCommand = function(db, collectionName, spec, document, options) {
|
||||
BaseCommand.call(this);
|
||||
|
||||
var object = spec;
|
||||
if(Buffer.isBuffer(object)) {
|
||||
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) {
|
||||
var error = new Error("update spec raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
var object = document;
|
||||
if(Buffer.isBuffer(object)) {
|
||||
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) {
|
||||
var error = new Error("update document raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
error.name = 'MongoError';
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
this.collectionName = collectionName;
|
||||
this.spec = spec;
|
||||
this.document = document;
|
||||
this.db = db;
|
||||
this.serializeFunctions = false;
|
||||
|
||||
// Generate correct flags
|
||||
var db_upsert = 0;
|
||||
var db_multi_update = 0;
|
||||
db_upsert = options != null && options['upsert'] != null ? (options['upsert'] == true ? 1 : 0) : db_upsert;
|
||||
db_multi_update = options != null && options['multi'] != null ? (options['multi'] == true ? 1 : 0) : db_multi_update;
|
||||
|
||||
// Flags
|
||||
this.flags = parseInt(db_multi_update.toString() + db_upsert.toString(), 2);
|
||||
// Let us defined on a command basis if we want functions to be serialized or not
|
||||
if(options['serializeFunctions'] != null && options['serializeFunctions']) {
|
||||
this.serializeFunctions = true;
|
||||
}
|
||||
};
|
||||
|
||||
inherits(UpdateCommand, BaseCommand);
|
||||
|
||||
UpdateCommand.OP_UPDATE = 2001;
|
||||
|
||||
/*
|
||||
struct {
|
||||
MsgHeader header; // standard message header
|
||||
int32 ZERO; // 0 - reserved for future use
|
||||
cstring fullCollectionName; // "dbname.collectionname"
|
||||
int32 flags; // bit vector. see below
|
||||
BSON spec; // the query to select the document
|
||||
BSON document; // the document data to update with or insert
|
||||
}
|
||||
*/
|
||||
UpdateCommand.prototype.toBinary = function() {
|
||||
// Calculate total length of the document
|
||||
var totalLengthOfCommand = 4 + Buffer.byteLength(this.collectionName) + 1 + 4 + this.db.bson.calculateObjectSize(this.spec, false, true) +
|
||||
this.db.bson.calculateObjectSize(this.document, this.serializeFunctions, true) + (4 * 4);
|
||||
|
||||
// Let's build the single pass buffer command
|
||||
var _index = 0;
|
||||
var _command = new Buffer(totalLengthOfCommand);
|
||||
// Write the header information to the buffer
|
||||
_command[_index + 3] = (totalLengthOfCommand >> 24) & 0xff;
|
||||
_command[_index + 2] = (totalLengthOfCommand >> 16) & 0xff;
|
||||
_command[_index + 1] = (totalLengthOfCommand >> 8) & 0xff;
|
||||
_command[_index] = totalLengthOfCommand & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write the request ID
|
||||
_command[_index + 3] = (this.requestId >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.requestId >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.requestId >> 8) & 0xff;
|
||||
_command[_index] = this.requestId & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
// Write the op_code for the command
|
||||
_command[_index + 3] = (UpdateCommand.OP_UPDATE >> 24) & 0xff;
|
||||
_command[_index + 2] = (UpdateCommand.OP_UPDATE >> 16) & 0xff;
|
||||
_command[_index + 1] = (UpdateCommand.OP_UPDATE >> 8) & 0xff;
|
||||
_command[_index] = UpdateCommand.OP_UPDATE & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Write zero
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
_command[_index++] = 0;
|
||||
|
||||
// Write the collection name to the command
|
||||
_index = _index + _command.write(this.collectionName, _index, 'utf8') + 1;
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Write the update flags
|
||||
_command[_index + 3] = (this.flags >> 24) & 0xff;
|
||||
_command[_index + 2] = (this.flags >> 16) & 0xff;
|
||||
_command[_index + 1] = (this.flags >> 8) & 0xff;
|
||||
_command[_index] = this.flags & 0xff;
|
||||
// Adjust index
|
||||
_index = _index + 4;
|
||||
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
var object = this.spec;
|
||||
|
||||
// Serialize the selector
|
||||
// If we are passing a raw buffer, do minimal validation
|
||||
if(Buffer.isBuffer(object)) {
|
||||
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
documentLength = object.length;
|
||||
// Copy the data into the current buffer
|
||||
object.copy(_command, _index);
|
||||
} else {
|
||||
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, false) - _index + 1;
|
||||
}
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
// Document binary length
|
||||
var documentLength = 0
|
||||
var object = this.document;
|
||||
|
||||
// Serialize the document
|
||||
// If we are passing a raw buffer, do minimal validation
|
||||
if(Buffer.isBuffer(object)) {
|
||||
var object_size = object[0] | object[1] << 8 | object[2] << 16 | object[3] << 24;
|
||||
if(object_size != object.length) throw new Error("raw message size does not match message header size [" + object.length + "] != [" + object_size + "]");
|
||||
documentLength = object.length;
|
||||
// Copy the data into the current buffer
|
||||
object.copy(_command, _index);
|
||||
} else {
|
||||
documentLength = this.db.bson.serializeWithBufferAndIndex(object, this.checkKeys, _command, _index, this.serializeFunctions) - _index + 1;
|
||||
}
|
||||
|
||||
// Write the length to the document
|
||||
_command[_index + 3] = (documentLength >> 24) & 0xff;
|
||||
_command[_index + 2] = (documentLength >> 16) & 0xff;
|
||||
_command[_index + 1] = (documentLength >> 8) & 0xff;
|
||||
_command[_index] = documentLength & 0xff;
|
||||
// Update index in buffer
|
||||
_index = _index + documentLength;
|
||||
// Add terminating 0 for the object
|
||||
_command[_index - 1] = 0;
|
||||
|
||||
return _command;
|
||||
};
|
||||
|
||||
// Constants
|
||||
UpdateCommand.DB_UPSERT = 0;
|
||||
UpdateCommand.DB_MULTI_UPDATE = 1;
|
||||
414
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection.js
generated
vendored
Normal file
414
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection.js
generated
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
var utils = require('./connection_utils'),
|
||||
inherits = require('util').inherits,
|
||||
net = require('net'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
inherits = require('util').inherits,
|
||||
binaryutils = require('../utils'),
|
||||
tls = require('tls');
|
||||
|
||||
var Connection = exports.Connection = function(id, socketOptions) {
|
||||
// Set up event emitter
|
||||
EventEmitter.call(this);
|
||||
// Store all socket options
|
||||
this.socketOptions = socketOptions ? socketOptions : {host:'localhost', port:27017};
|
||||
// Id for the connection
|
||||
this.id = id;
|
||||
// State of the connection
|
||||
this.connected = false;
|
||||
|
||||
//
|
||||
// Connection parsing state
|
||||
//
|
||||
this.maxBsonSize = socketOptions.maxBsonSize ? socketOptions.maxBsonSize : Connection.DEFAULT_MAX_BSON_SIZE;
|
||||
// Contains the current message bytes
|
||||
this.buffer = null;
|
||||
// Contains the current message size
|
||||
this.sizeOfMessage = 0;
|
||||
// Contains the readIndex for the messaage
|
||||
this.bytesRead = 0;
|
||||
// Contains spill over bytes from additional messages
|
||||
this.stubBuffer = 0;
|
||||
|
||||
// Just keeps list of events we allow
|
||||
this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[], end:[]};
|
||||
|
||||
// Just keeps list of events we allow
|
||||
resetHandlers(this, false);
|
||||
}
|
||||
|
||||
// Set max bson size
|
||||
Connection.DEFAULT_MAX_BSON_SIZE = 1024 * 1024 * 4;
|
||||
|
||||
// Inherit event emitter so we can emit stuff wohoo
|
||||
inherits(Connection, EventEmitter);
|
||||
|
||||
Connection.prototype.start = function() {
|
||||
// If we have a normal connection
|
||||
if(this.socketOptions.ssl) {
|
||||
// Create a new stream
|
||||
this.connection = new net.Socket();
|
||||
// Set options on the socket
|
||||
this.connection.setTimeout(this.socketOptions.timeout);
|
||||
// Work around for 0.4.X
|
||||
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
|
||||
// Set keep alive if defined
|
||||
if(process.version.indexOf("v0.4") == -1) {
|
||||
if(this.socketOptions.keepAlive > 0) {
|
||||
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
|
||||
} else {
|
||||
this.connection.setKeepAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up pair for tls with server, accept self-signed certificates as well
|
||||
var pair = this.pair = tls.createSecurePair(false);
|
||||
// Set up encrypted streams
|
||||
this.pair.encrypted.pipe(this.connection);
|
||||
this.connection.pipe(this.pair.encrypted);
|
||||
|
||||
// Setup clearText stream
|
||||
this.writeSteam = this.pair.cleartext;
|
||||
// Add all handlers to the socket to manage it
|
||||
this.pair.on("secure", connectHandler(this));
|
||||
this.pair.cleartext.on("data", createDataHandler(this));
|
||||
// Add handlers
|
||||
this.connection.on("error", errorHandler(this));
|
||||
// this.connection.on("connect", connectHandler(this));
|
||||
this.connection.on("end", endHandler(this));
|
||||
this.connection.on("timeout", timeoutHandler(this));
|
||||
this.connection.on("drain", drainHandler(this));
|
||||
this.writeSteam.on("close", closeHandler(this));
|
||||
// Start socket
|
||||
this.connection.connect(this.socketOptions.port, this.socketOptions.host);
|
||||
} else {
|
||||
// Create new connection instance
|
||||
this.connection = net.createConnection(this.socketOptions.port, this.socketOptions.host);
|
||||
// Set options on the socket
|
||||
this.connection.setTimeout(this.socketOptions.timeout);
|
||||
// Work around for 0.4.X
|
||||
if(process.version.indexOf("v0.4") == -1) this.connection.setNoDelay(this.socketOptions.noDelay);
|
||||
// Set keep alive if defined
|
||||
if(process.version.indexOf("v0.4") == -1) {
|
||||
if(this.socketOptions.keepAlive > 0) {
|
||||
this.connection.setKeepAlive(true, this.socketOptions.keepAlive);
|
||||
} else {
|
||||
this.connection.setKeepAlive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Set up write stream
|
||||
this.writeSteam = this.connection;
|
||||
// Add handlers
|
||||
this.connection.on("error", errorHandler(this));
|
||||
// Add all handlers to the socket to manage it
|
||||
this.connection.on("connect", connectHandler(this));
|
||||
// this.connection.on("end", endHandler(this));
|
||||
this.connection.on("data", createDataHandler(this));
|
||||
this.connection.on("timeout", timeoutHandler(this));
|
||||
this.connection.on("drain", drainHandler(this));
|
||||
this.connection.on("close", closeHandler(this));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the sockets are live
|
||||
Connection.prototype.isConnected = function() {
|
||||
return this.connected && !this.connection.destroyed && this.connection.writable && this.connection.readable;
|
||||
}
|
||||
|
||||
// Write the data out to the socket
|
||||
Connection.prototype.write = function(command, callback) {
|
||||
try {
|
||||
// If we have a list off commands to be executed on the same socket
|
||||
if(Array.isArray(command)) {
|
||||
for(var i = 0; i < command.length; i++) {
|
||||
var binaryCommand = command[i].toBinary()
|
||||
if(binaryCommand.length > this.maxBsonSize) return callback(new Error("Document exceeds maximal allowed bson size of " + this.maxBsonSize + " bytes"));
|
||||
if(this.logger != null && this.logger.doDebug) this.logger.debug("writing command to mongodb", binaryCommand);
|
||||
var r = this.writeSteam.write(binaryCommand);
|
||||
}
|
||||
} else {
|
||||
var binaryCommand = command.toBinary()
|
||||
if(binaryCommand.length > this.maxBsonSize) return callback(new Error("Document exceeds maximal allowed bson size of " + this.maxBsonSize + " bytes"));
|
||||
if(this.logger != null && this.logger.doDebug) this.logger.debug("writing command to mongodb", binaryCommand);
|
||||
var r = this.writeSteam.write(binaryCommand);
|
||||
}
|
||||
} catch (err) {
|
||||
if(typeof callback === 'function') callback(err);
|
||||
}
|
||||
}
|
||||
|
||||
// Force the closure of the connection
|
||||
Connection.prototype.close = function() {
|
||||
// clear out all the listeners
|
||||
resetHandlers(this, true);
|
||||
// Add a dummy error listener to catch any weird last moment errors (and ignore them)
|
||||
this.connection.on("error", function() {})
|
||||
// destroy connection
|
||||
this.connection.destroy();
|
||||
}
|
||||
|
||||
// Reset all handlers
|
||||
var resetHandlers = function(self, clearListeners) {
|
||||
self.eventHandlers = {error:[], connect:[], close:[], end:[], timeout:[], parseError:[], message:[]};
|
||||
|
||||
// If we want to clear all the listeners
|
||||
if(clearListeners && self.connection != null) {
|
||||
var keys = Object.keys(self.eventHandlers);
|
||||
// Remove all listeners
|
||||
for(var i = 0; i < keys.length; i++) {
|
||||
self.connection.removeAllListeners(keys[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handlers
|
||||
//
|
||||
|
||||
// Connect handler
|
||||
var connectHandler = function(self) {
|
||||
return function() {
|
||||
// Set connected
|
||||
self.connected = true;
|
||||
// Emit the connect event with no error
|
||||
self.emit("connect", null, self);
|
||||
}
|
||||
}
|
||||
|
||||
var createDataHandler = exports.Connection.createDataHandler = function(self) {
|
||||
// We need to handle the parsing of the data
|
||||
// and emit the messages when there is a complete one
|
||||
return function(data) {
|
||||
// Parse until we are done with the data
|
||||
while(data.length > 0) {
|
||||
// If we still have bytes to read on the current message
|
||||
if(self.bytesRead > 0 && self.sizeOfMessage > 0) {
|
||||
// Calculate the amount of remaining bytes
|
||||
var remainingBytesToRead = self.sizeOfMessage - self.bytesRead;
|
||||
// Check if the current chunk contains the rest of the message
|
||||
if(remainingBytesToRead > data.length) {
|
||||
// Copy the new data into the exiting buffer (should have been allocated when we know the message size)
|
||||
data.copy(self.buffer, self.bytesRead);
|
||||
// Adjust the number of bytes read so it point to the correct index in the buffer
|
||||
self.bytesRead = self.bytesRead + data.length;
|
||||
|
||||
// Reset state of buffer
|
||||
data = new Buffer(0);
|
||||
} else {
|
||||
// Copy the missing part of the data into our current buffer
|
||||
data.copy(self.buffer, self.bytesRead, 0, remainingBytesToRead);
|
||||
// Slice the overflow into a new buffer that we will then re-parse
|
||||
data = data.slice(remainingBytesToRead);
|
||||
|
||||
// Emit current complete message
|
||||
try {
|
||||
var emitBuffer = self.buffer;
|
||||
// Reset state of buffer
|
||||
self.buffer = null;
|
||||
self.sizeOfMessage = 0;
|
||||
self.bytesRead = 0;
|
||||
self.stubBuffer = null;
|
||||
// Emit the buffer
|
||||
self.emit("message", emitBuffer, self);
|
||||
} catch(err) {
|
||||
var errorObject = {err:"socketHandler", trace:err, bin:buffer, parseState:{
|
||||
sizeOfMessage:self.sizeOfMessage,
|
||||
bytesRead:self.bytesRead,
|
||||
stubBuffer:self.stubBuffer}};
|
||||
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
|
||||
// We got a parse Error fire it off then keep going
|
||||
self.emit("parseError", errorObject, self);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Stub buffer is kept in case we don't get enough bytes to determine the
|
||||
// size of the message (< 4 bytes)
|
||||
if(self.stubBuffer != null && self.stubBuffer.length > 0) {
|
||||
|
||||
// If we have enough bytes to determine the message size let's do it
|
||||
if(self.stubBuffer.length + data.length > 4) {
|
||||
// Prepad the data
|
||||
var newData = new Buffer(self.stubBuffer.length + data.length);
|
||||
self.stubBuffer.copy(newData, 0);
|
||||
data.copy(newData, self.stubBuffer.length);
|
||||
// Reassign for parsing
|
||||
data = newData;
|
||||
|
||||
// Reset state of buffer
|
||||
self.buffer = null;
|
||||
self.sizeOfMessage = 0;
|
||||
self.bytesRead = 0;
|
||||
self.stubBuffer = null;
|
||||
|
||||
} else {
|
||||
|
||||
// Add the the bytes to the stub buffer
|
||||
var newStubBuffer = new Buffer(self.stubBuffer.length + data.length);
|
||||
// Copy existing stub buffer
|
||||
self.stubBuffer.copy(newStubBuffer, 0);
|
||||
// Copy missing part of the data
|
||||
data.copy(newStubBuffer, self.stubBuffer.length);
|
||||
// Exit parsing loop
|
||||
data = new Buffer(0);
|
||||
}
|
||||
} else {
|
||||
if(data.length > 4) {
|
||||
// Retrieve the message size
|
||||
var sizeOfMessage = binaryutils.decodeUInt32(data, 0);
|
||||
// If we have a negative sizeOfMessage emit error and return
|
||||
if(sizeOfMessage < 0 || sizeOfMessage > self.maxBsonSize) {
|
||||
var errorObject = {err:"socketHandler", trace:'', bin:self.buffer, parseState:{
|
||||
sizeOfMessage:sizeOfMessage,
|
||||
bytesRead:self.bytesRead,
|
||||
stubBuffer:self.stubBuffer}};
|
||||
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
|
||||
// We got a parse Error fire it off then keep going
|
||||
self.emit("parseError", errorObject, self);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure that the size of message is larger than 0 and less than the max allowed
|
||||
if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage > data.length) {
|
||||
self.buffer = new Buffer(sizeOfMessage);
|
||||
// Copy all the data into the buffer
|
||||
data.copy(self.buffer, 0);
|
||||
// Update bytes read
|
||||
self.bytesRead = data.length;
|
||||
// Update sizeOfMessage
|
||||
self.sizeOfMessage = sizeOfMessage;
|
||||
// Ensure stub buffer is null
|
||||
self.stubBuffer = null;
|
||||
// Exit parsing loop
|
||||
data = new Buffer(0);
|
||||
|
||||
} else if(sizeOfMessage > 4 && sizeOfMessage < self.maxBsonSize && sizeOfMessage == data.length) {
|
||||
try {
|
||||
var emitBuffer = data;
|
||||
// Reset state of buffer
|
||||
self.buffer = null;
|
||||
self.sizeOfMessage = 0;
|
||||
self.bytesRead = 0;
|
||||
self.stubBuffer = null;
|
||||
// Exit parsing loop
|
||||
data = new Buffer(0);
|
||||
// Emit the message
|
||||
self.emit("message", emitBuffer, self);
|
||||
} catch (err) {
|
||||
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
|
||||
sizeOfMessage:self.sizeOfMessage,
|
||||
bytesRead:self.bytesRead,
|
||||
stubBuffer:self.stubBuffer}};
|
||||
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
|
||||
// We got a parse Error fire it off then keep going
|
||||
self.emit("parseError", errorObject, self);
|
||||
}
|
||||
} else if(sizeOfMessage <= 4 || sizeOfMessage > self.maxBsonSize) {
|
||||
var errorObject = {err:"socketHandler", trace:null, bin:data, parseState:{
|
||||
sizeOfMessage:sizeOfMessage,
|
||||
bytesRead:0,
|
||||
buffer:null,
|
||||
stubBuffer:null}};
|
||||
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
|
||||
// We got a parse Error fire it off then keep going
|
||||
self.emit("parseError", errorObject, self);
|
||||
|
||||
// Clear out the state of the parser
|
||||
self.buffer = null;
|
||||
self.sizeOfMessage = 0;
|
||||
self.bytesRead = 0;
|
||||
self.stubBuffer = null;
|
||||
// Exit parsing loop
|
||||
data = new Buffer(0);
|
||||
|
||||
} else {
|
||||
try {
|
||||
var emitBuffer = data.slice(0, sizeOfMessage);
|
||||
// Reset state of buffer
|
||||
self.buffer = null;
|
||||
self.sizeOfMessage = 0;
|
||||
self.bytesRead = 0;
|
||||
self.stubBuffer = null;
|
||||
// Copy rest of message
|
||||
data = data.slice(sizeOfMessage);
|
||||
// Emit the message
|
||||
self.emit("message", emitBuffer, self);
|
||||
} catch (err) {
|
||||
var errorObject = {err:"socketHandler", trace:err, bin:self.buffer, parseState:{
|
||||
sizeOfMessage:sizeOfMessage,
|
||||
bytesRead:self.bytesRead,
|
||||
stubBuffer:self.stubBuffer}};
|
||||
if(self.logger != null && self.logger.doError) self.logger.error("parseError", errorObject);
|
||||
// We got a parse Error fire it off then keep going
|
||||
self.emit("parseError", errorObject, self);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
// Create a buffer that contains the space for the non-complete message
|
||||
self.stubBuffer = new Buffer(data.length)
|
||||
// Copy the data to the stub buffer
|
||||
data.copy(self.stubBuffer, 0);
|
||||
// Exit parsing loop
|
||||
data = new Buffer(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var endHandler = function(self) {
|
||||
return function() {
|
||||
// Set connected to false
|
||||
self.connected = false;
|
||||
// Emit end event
|
||||
self.emit("end", {err: 'connection received Fin packet from [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
|
||||
}
|
||||
}
|
||||
|
||||
var timeoutHandler = function(self) {
|
||||
return function() {
|
||||
self.emit("timeout", {err: 'connection to [' + self.socketOptions.host + ':' + self.socketOptions.port + '] timed out'}, self);
|
||||
}
|
||||
}
|
||||
|
||||
var drainHandler = function(self) {
|
||||
return function() {
|
||||
}
|
||||
}
|
||||
|
||||
var errorHandler = function(self) {
|
||||
return function(err) {
|
||||
// Set connected to false
|
||||
self.connected = false;
|
||||
// Emit error
|
||||
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
|
||||
}
|
||||
}
|
||||
|
||||
var closeHandler = function(self) {
|
||||
return function(hadError) {
|
||||
// If we have an error during the connection phase
|
||||
if(hadError && !self.connected) {
|
||||
// Set disconnected
|
||||
self.connected = false;
|
||||
// Emit error
|
||||
self.emit("error", {err: 'failed to connect to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
|
||||
} else {
|
||||
// Set disconnected
|
||||
self.connected = false;
|
||||
// Emit close
|
||||
self.emit("close", {err: 'connection closed to [' + self.socketOptions.host + ':' + self.socketOptions.port + ']'}, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Some basic defaults
|
||||
Connection.DEFAULT_PORT = 27017;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
250
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection_pool.js
generated
vendored
Normal file
250
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection_pool.js
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
var utils = require('./connection_utils'),
|
||||
inherits = require('util').inherits,
|
||||
net = require('net'),
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
inherits = require('util').inherits,
|
||||
MongoReply = require("../responses/mongo_reply").MongoReply,
|
||||
Connection = require("./connection").Connection;
|
||||
|
||||
var ConnectionPool = exports.ConnectionPool = function(host, port, poolSize, bson, socketOptions) {
|
||||
if(typeof host !== 'string' || typeof port !== 'number') throw "host and port must be specified [" + host + ":" + port + "]";
|
||||
// Set up event emitter
|
||||
EventEmitter.call(this);
|
||||
// Keep all options for the socket in a specific collection allowing the user to specify the
|
||||
// Wished upon socket connection parameters
|
||||
this.socketOptions = typeof socketOptions === 'object' ? socketOptions : {};
|
||||
this.socketOptions.host = host;
|
||||
this.socketOptions.port = port;
|
||||
this.bson = bson;
|
||||
// PoolSize is always + 1 for special reserved "measurment" socket (like ping, stats etc)
|
||||
this.poolSize = poolSize;
|
||||
this.minPoolSize = Math.floor(this.poolSize / 2) + 1;
|
||||
|
||||
// Set default settings for the socket options
|
||||
utils.setIntegerParameter(this.socketOptions, 'timeout', 0);
|
||||
// Delay before writing out the data to the server
|
||||
utils.setBooleanParameter(this.socketOptions, 'noDelay', true);
|
||||
// Delay before writing out the data to the server
|
||||
utils.setIntegerParameter(this.socketOptions, 'keepAlive', 0);
|
||||
// Set the encoding of the data read, default is binary == null
|
||||
utils.setStringParameter(this.socketOptions, 'encoding', null);
|
||||
// Allows you to set a throttling bufferSize if you need to stop overflows
|
||||
utils.setIntegerParameter(this.socketOptions, 'bufferSize', 0);
|
||||
|
||||
// Internal structures
|
||||
this.openConnections = [];
|
||||
// Assign connection id's
|
||||
this.connectionId = 0;
|
||||
|
||||
// Current index for selection of pool connection
|
||||
this.currentConnectionIndex = 0;
|
||||
// The pool state
|
||||
this._poolState = 'disconnected';
|
||||
// timeout control
|
||||
this._timeout = false;
|
||||
}
|
||||
|
||||
inherits(ConnectionPool, EventEmitter);
|
||||
|
||||
ConnectionPool.prototype.setMaxBsonSize = function(maxBsonSize) {
|
||||
if(maxBsonSize == null){
|
||||
maxBsonSize = Connection.DEFAULT_MAX_BSON_SIZE;
|
||||
}
|
||||
|
||||
for(var i = 0; i < this.openConnections.length; i++) {
|
||||
this.openConnections[i].maxBsonSize = maxBsonSize;
|
||||
}
|
||||
}
|
||||
|
||||
// Start a function
|
||||
var _connect = function(_self) {
|
||||
return new function() {
|
||||
var connectionStatus = _self._poolState;
|
||||
// Create a new connection instance
|
||||
var connection = new Connection(_self.connectionId++, _self.socketOptions);
|
||||
// Set logger on pool
|
||||
connection.logger = _self.logger;
|
||||
// Connect handler
|
||||
connection.on("connect", function(err, connection) {
|
||||
// Add connection to list of open connections
|
||||
_self.openConnections.push(connection);
|
||||
// If the number of open connections is equal to the poolSize signal ready pool
|
||||
if(_self.openConnections.length === _self.poolSize && _self._poolState !== 'disconnected') {
|
||||
// Set connected
|
||||
_self._poolState = 'connected';
|
||||
// Emit pool ready
|
||||
_self.emit("poolReady");
|
||||
} else if(_self.openConnections.length < _self.poolSize) {
|
||||
// We need to open another connection, make sure it's in the next
|
||||
// tick so we don't get a cascade of errors
|
||||
process.nextTick(function() {
|
||||
_connect(_self);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var numberOfErrors = 0
|
||||
|
||||
// Error handler
|
||||
connection.on("error", function(err, connection) {
|
||||
numberOfErrors++;
|
||||
// If we are already disconnected ignore the event
|
||||
if(connectionStatus != 'disconnected' && _self.listeners("error").length > 0) {
|
||||
_self.emit("error", err);
|
||||
}
|
||||
|
||||
// Set disconnected
|
||||
connectionStatus = 'disconnected';
|
||||
// Set disconnected
|
||||
_self._poolState = 'disconnected';
|
||||
// Stop
|
||||
_self.stop();
|
||||
});
|
||||
|
||||
// Close handler
|
||||
connection.on("close", function() {
|
||||
// If we are already disconnected ignore the event
|
||||
if(connectionStatus !== 'disconnected' && _self.listeners("close").length > 0) {
|
||||
_self.emit("close");
|
||||
}
|
||||
|
||||
// Set disconnected
|
||||
connectionStatus = 'disconnected';
|
||||
// Set disconnected
|
||||
_self._poolState = 'disconnected';
|
||||
// Stop
|
||||
_self.stop();
|
||||
});
|
||||
|
||||
// Timeout handler
|
||||
connection.on("timeout", function(err, connection) {
|
||||
// If we are already disconnected ignore the event
|
||||
if(connectionStatus !== 'disconnected' && _self.listeners("timeout").length > 0) {
|
||||
_self.emit("timeout", err);
|
||||
}
|
||||
|
||||
// Set disconnected
|
||||
connectionStatus = 'disconnected';
|
||||
// Set disconnected
|
||||
_self._poolState = 'disconnected';
|
||||
// Stop
|
||||
_self.stop();
|
||||
});
|
||||
|
||||
// Parse error, needs a complete shutdown of the pool
|
||||
connection.on("parseError", function() {
|
||||
// If we are already disconnected ignore the event
|
||||
if(connectionStatus !== 'disconnected' && _self.listeners("parseError").length > 0) {
|
||||
_self.emit("parseError", new Error("parseError occured"));
|
||||
}
|
||||
|
||||
// Set disconnected
|
||||
connectionStatus = 'disconnected';
|
||||
_self.stop();
|
||||
});
|
||||
|
||||
connection.on("message", function(message) {
|
||||
_self.emit("message", message);
|
||||
});
|
||||
|
||||
// Start connection in the next tick
|
||||
connection.start();
|
||||
}();
|
||||
}
|
||||
|
||||
|
||||
// Start method, will throw error if no listeners are available
|
||||
// Pass in an instance of the listener that contains the api for
|
||||
// finding callbacks for a given message etc.
|
||||
ConnectionPool.prototype.start = function() {
|
||||
var markerDate = new Date().getTime();
|
||||
var self = this;
|
||||
|
||||
if(this.listeners("poolReady").length == 0) {
|
||||
throw "pool must have at least one listener ready that responds to the [poolReady] event";
|
||||
}
|
||||
|
||||
// Set pool state to connecting
|
||||
this._poolState = 'connecting';
|
||||
this._timeout = false;
|
||||
|
||||
_connect(self);
|
||||
}
|
||||
|
||||
// Restart a connection pool (on a close the pool might be in a wrong state)
|
||||
ConnectionPool.prototype.restart = function() {
|
||||
// Close all connections
|
||||
this.stop(false);
|
||||
// Now restart the pool
|
||||
this.start();
|
||||
}
|
||||
|
||||
// Stop the connections in the pool
|
||||
ConnectionPool.prototype.stop = function(removeListeners) {
|
||||
removeListeners = removeListeners == null ? true : removeListeners;
|
||||
// Set disconnected
|
||||
this._poolState = 'disconnected';
|
||||
|
||||
// Clear all listeners if specified
|
||||
if(removeListeners) {
|
||||
this.removeAllEventListeners();
|
||||
}
|
||||
|
||||
// Close all connections
|
||||
for(var i = 0; i < this.openConnections.length; i++) {
|
||||
this.openConnections[i].close();
|
||||
}
|
||||
|
||||
// Clean up
|
||||
this.openConnections = [];
|
||||
}
|
||||
|
||||
// Check the status of the connection
|
||||
ConnectionPool.prototype.isConnected = function() {
|
||||
return this._poolState === 'connected';
|
||||
}
|
||||
|
||||
// Checkout a connection from the pool for usage, or grab a specific pool instance
|
||||
ConnectionPool.prototype.checkoutConnection = function(id) {
|
||||
var index = (this.currentConnectionIndex++ % (this.openConnections.length));
|
||||
var connection = this.openConnections[index];
|
||||
return connection;
|
||||
}
|
||||
|
||||
ConnectionPool.prototype.getAllConnections = function() {
|
||||
return this.openConnections;
|
||||
}
|
||||
|
||||
// Remove all non-needed event listeners
|
||||
ConnectionPool.prototype.removeAllEventListeners = function() {
|
||||
this.removeAllListeners("close");
|
||||
this.removeAllListeners("error");
|
||||
this.removeAllListeners("timeout");
|
||||
this.removeAllListeners("connect");
|
||||
this.removeAllListeners("end");
|
||||
this.removeAllListeners("parseError");
|
||||
this.removeAllListeners("message");
|
||||
this.removeAllListeners("poolReady");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
23
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection_utils.js
generated
vendored
Normal file
23
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/connection_utils.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
exports.setIntegerParameter = function(object, field, defaultValue) {
|
||||
if(object[field] == null) {
|
||||
object[field] = defaultValue;
|
||||
} else if(typeof object[field] !== "number" && object[field] !== parseInt(object[field], 10)) {
|
||||
throw "object field [" + field + "] must be a numeric integer value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
exports.setBooleanParameter = function(object, field, defaultValue) {
|
||||
if(object[field] == null) {
|
||||
object[field] = defaultValue;
|
||||
} else if(typeof object[field] !== "boolean") {
|
||||
throw "object field [" + field + "] must be a boolean value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
|
||||
}
|
||||
}
|
||||
|
||||
exports.setStringParameter = function(object, field, defaultValue) {
|
||||
if(object[field] == null) {
|
||||
object[field] = defaultValue;
|
||||
} else if(typeof object[field] !== "string") {
|
||||
throw "object field [" + field + "] must be a string value, attempted to set to [" + object[field] + "] type of [" + typeof object[field] + "]";
|
||||
}
|
||||
}
|
||||
1230
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/repl_set.js
generated
vendored
Normal file
1230
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/repl_set.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
745
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/server.js
generated
vendored
Normal file
745
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/server.js
generated
vendored
Normal file
@@ -0,0 +1,745 @@
|
||||
var Connection = require('./connection').Connection,
|
||||
DbCommand = require('../commands/db_command').DbCommand,
|
||||
MongoReply = require('../responses/mongo_reply').MongoReply,
|
||||
ConnectionPool = require('./connection_pool').ConnectionPool,
|
||||
EventEmitter = require('events').EventEmitter,
|
||||
inherits = require('util').inherits;
|
||||
|
||||
/**
|
||||
* Class representing a single MongoDB Server connection
|
||||
*
|
||||
* Options
|
||||
* - **readPreference** {String, default:null}, set's the read preference (Server.READ_PRIMAR, Server.READ_SECONDARY_ONLY, Server.READ_SECONDARY)
|
||||
* - **ssl** {Boolean, default:false}, use ssl connection (needs to have a mongod server with ssl support)
|
||||
* - **slaveOk** {Boolean, default:false}, legacy option allowing reads from secondary, use **readPrefrence** instead.
|
||||
* - **poolSize** {Number, default:1}, number of connections in the connection pool, set to 1 as default for legacy reasons.
|
||||
* - **socketOptions** {Object, default:null}, an object containing socket options to use (noDelay:(boolean), keepAlive:(number), timeout:(number))
|
||||
* - **logger** {Object, default:null}, an object representing a logger that you want to use, needs to support functions debug, log, error **({error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}})**.
|
||||
* - **auto_reconnect** {Boolean, default:false}, reconnect on error.
|
||||
*
|
||||
* @class Represents a Server connection.
|
||||
* @param {String} host the server host
|
||||
* @param {Number} port the server port
|
||||
* @param {Object} [options] optional options for insert command
|
||||
*/
|
||||
function Server(host, port, options) {
|
||||
// Set up event emitter
|
||||
EventEmitter.call(this);
|
||||
// Set up Server instance
|
||||
if(!(this instanceof Server)) return new Server(host, port, options);
|
||||
|
||||
var self = this;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.options = options == null ? {} : options;
|
||||
this.internalConnection;
|
||||
this.internalMaster = false;
|
||||
this.connected = false;
|
||||
this.poolSize = this.options.poolSize == null ? 1 : this.options.poolSize;
|
||||
this.ssl = this.options.ssl == null ? false : this.options.ssl;
|
||||
this.slaveOk = this.options["slave_ok"];
|
||||
this._used = false;
|
||||
|
||||
// Get the readPreference
|
||||
var readPreference = this.options['readPreference'];
|
||||
// Read preference setting
|
||||
if(readPreference != null) {
|
||||
if(readPreference != Server.READ_PRIMARY && readPreference != Server.READ_SECONDARY_ONLY
|
||||
&& readPreference != Server.READ_SECONDARY) {
|
||||
throw new Error("Illegal readPreference mode specified, " + readPreference);
|
||||
}
|
||||
|
||||
// Set read Preference
|
||||
this._readPreference = readPreference;
|
||||
} else {
|
||||
this._readPreference = null;
|
||||
}
|
||||
|
||||
// Contains the isMaster information returned from the server
|
||||
this.isMasterDoc;
|
||||
|
||||
// Set default connection pool options
|
||||
this.socketOptions = this.options.socketOptions != null ? this.options.socketOptions : {};
|
||||
// Set ssl up if it's defined
|
||||
if(this.ssl) {
|
||||
this.socketOptions.ssl = true;
|
||||
}
|
||||
|
||||
// Set up logger if any set
|
||||
this.logger = this.options.logger != null
|
||||
&& (typeof this.options.logger.debug == 'function')
|
||||
&& (typeof this.options.logger.error == 'function')
|
||||
&& (typeof this.options.logger.log == 'function')
|
||||
? this.options.logger : {error:function(message, object) {}, log:function(message, object) {}, debug:function(message, object) {}};
|
||||
|
||||
// Just keeps list of events we allow
|
||||
this.eventHandlers = {error:[], parseError:[], poolReady:[], message:[], close:[], timeout:[]};
|
||||
// Internal state of server connection
|
||||
this._serverState = 'disconnected';
|
||||
// this._timeout = false;
|
||||
// Contains state information about server connection
|
||||
this._state = {'runtimeStats': {'queryStats':new RunningStats()}};
|
||||
// Do we record server stats or not
|
||||
this.recordQueryStats = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
// Inherit simple event emitter
|
||||
inherits(Server, EventEmitter);
|
||||
// Read Preferences
|
||||
Server.READ_PRIMARY = 'primary';
|
||||
Server.READ_SECONDARY = 'secondary';
|
||||
Server.READ_SECONDARY_ONLY = 'secondaryOnly';
|
||||
// Always ourselves
|
||||
Server.prototype.setReadPreference = function() {}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype._isUsed = function() {
|
||||
return this._used;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.close = function(callback) {
|
||||
// Remove all local listeners
|
||||
this.removeAllListeners();
|
||||
|
||||
if(this.connectionPool != null) {
|
||||
// Remove all the listeners on the pool so it does not fire messages all over the place
|
||||
this.connectionPool.removeAllEventListeners();
|
||||
// Close the connection if it's open
|
||||
this.connectionPool.stop(true);
|
||||
}
|
||||
|
||||
// Set server status as disconnected
|
||||
this._serverState = 'disconnected';
|
||||
// Peform callback if present
|
||||
if(typeof callback === 'function') callback();
|
||||
};
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.isConnected = function() {
|
||||
return this._serverState == 'connected';
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.allServerInstances = function() {
|
||||
return [this];
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.isSetMember = function() {
|
||||
return this['replicasetInstance'] != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.connect = function(dbInstance, options, callback) {
|
||||
if('function' === typeof options) callback = options, options = {};
|
||||
if(options == null) options = {};
|
||||
if(!('function' === typeof callback)) callback = null;
|
||||
|
||||
// Currently needed to work around problems with multiple connections in a pool with ssl
|
||||
// TODO fix if possible
|
||||
if(this.ssl == true) {
|
||||
// Set up socket options for ssl
|
||||
this.socketOptions.ssl = true;
|
||||
}
|
||||
|
||||
// Let's connect
|
||||
var server = this;
|
||||
// Let's us override the main receiver of events
|
||||
var eventReceiver = options.eventReceiver != null ? options.eventReceiver : this;
|
||||
// Creating dbInstance
|
||||
this.dbInstance = dbInstance;
|
||||
// Save reference to dbInstance
|
||||
this.dbInstances = [dbInstance];
|
||||
|
||||
// Set server state to connecting
|
||||
this._serverState = 'connecting';
|
||||
// Ensure dbInstance can do a slave query if it's set
|
||||
dbInstance.slaveOk = this.slaveOk ? this.slaveOk : dbInstance.slaveOk;
|
||||
// Create connection Pool instance with the current BSON serializer
|
||||
var connectionPool = new ConnectionPool(this.host, this.port, this.poolSize, dbInstance.bson, this.socketOptions);
|
||||
// Set logger on pool
|
||||
connectionPool.logger = this.logger;
|
||||
|
||||
// Set up a new pool using default settings
|
||||
server.connectionPool = connectionPool;
|
||||
|
||||
// Set basic parameters passed in
|
||||
var returnIsMasterResults = options.returnIsMasterResults == null ? false : options.returnIsMasterResults;
|
||||
|
||||
// Create a default connect handler, overriden when using replicasets
|
||||
var connectCallback = function(err, reply) {
|
||||
// ensure no callbacks get called twice
|
||||
var internalCallback = callback;
|
||||
callback = null;
|
||||
// If something close down the connection and removed the callback before
|
||||
// proxy killed connection etc, ignore the erorr as close event was isssued
|
||||
if(err != null && internalCallback == null) return;
|
||||
// Internal callback
|
||||
if(err != null) return internalCallback(err, null);
|
||||
server.master = reply.documents[0].ismaster == 1 ? true : false;
|
||||
server.connectionPool.setMaxBsonSize(reply.documents[0].maxBsonObjectSize);
|
||||
// Set server as connected
|
||||
server.connected = true;
|
||||
// Save document returned so we can query it
|
||||
server.isMasterDoc = reply.documents[0];
|
||||
|
||||
// If we have it set to returnIsMasterResults
|
||||
if(returnIsMasterResults) {
|
||||
internalCallback(null, reply);
|
||||
} else {
|
||||
internalCallback(null, dbInstance);
|
||||
}
|
||||
};
|
||||
|
||||
// Let's us override the main connect callback
|
||||
var connectHandler = options.connectHandler == null ? connectCallback : options.connectHandler;
|
||||
|
||||
// Set up on connect method
|
||||
connectionPool.on("poolReady", function() {
|
||||
// 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.NcreateIsMasterCommand(dbInstance, dbInstance.databaseName);
|
||||
// Check out a reader from the pool
|
||||
var connection = connectionPool.checkoutConnection();
|
||||
// Set server state to connected
|
||||
server._serverState = 'connected';
|
||||
|
||||
// Register handler for messages
|
||||
dbInstance._registerHandler(db_command, false, connection, connectHandler);
|
||||
|
||||
// Write the command out
|
||||
connection.write(db_command);
|
||||
})
|
||||
|
||||
// Set up item connection
|
||||
connectionPool.on("message", function(message) {
|
||||
// Attempt to parse the message
|
||||
try {
|
||||
// Create a new mongo reply
|
||||
var mongoReply = new MongoReply()
|
||||
// Parse the header
|
||||
mongoReply.parseHeader(message, connectionPool.bson)
|
||||
// If message size is not the same as the buffer size
|
||||
// something went terribly wrong somewhere
|
||||
if(mongoReply.messageLength != message.length) {
|
||||
// Emit the error
|
||||
if(eventReceiver.listeners["error"] && eventReceiver.listeners["error"].length > 0) eventReceiver.emit("error", new Error("bson length is different from message length"), server);
|
||||
// Remove all listeners
|
||||
server.removeAllListeners();
|
||||
} else {
|
||||
var startDate = new Date().getTime();
|
||||
|
||||
// Callback instance
|
||||
var callbackInfo = null;
|
||||
var dbInstanceObject = null;
|
||||
|
||||
// Locate a callback instance and remove any additional ones
|
||||
for(var i = 0; i < server.dbInstances.length; i++) {
|
||||
var dbInstanceObjectTemp = server.dbInstances[i];
|
||||
var hasHandler = dbInstanceObjectTemp._hasHandler(mongoReply.responseTo.toString());
|
||||
// Assign the first one we find and remove any duplicate ones
|
||||
if(hasHandler && callbackInfo == null) {
|
||||
callbackInfo = dbInstanceObjectTemp._findHandler(mongoReply.responseTo.toString());
|
||||
dbInstanceObject = dbInstanceObjectTemp;
|
||||
} else if(hasHandler) {
|
||||
dbInstanceObjectTemp._removeHandler(mongoReply.responseTo.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Only execute callback if we have a caller
|
||||
if(callbackInfo.callback && Array.isArray(callbackInfo.info.chained)) {
|
||||
// Check if callback has already been fired (missing chain command)
|
||||
var chained = callbackInfo.info.chained;
|
||||
var numberOfFoundCallbacks = 0;
|
||||
for(var i = 0; i < chained.length; i++) {
|
||||
if(dbInstanceObject._hasHandler(chained[i])) numberOfFoundCallbacks++;
|
||||
}
|
||||
|
||||
// If we have already fired then clean up rest of chain and move on
|
||||
if(numberOfFoundCallbacks != chained.length) {
|
||||
for(var i = 0; i < chained.length; i++) {
|
||||
dbInstanceObject._removeHandler(chained[i]);
|
||||
}
|
||||
|
||||
// Just return from function
|
||||
return;
|
||||
}
|
||||
|
||||
// Parse the body
|
||||
mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
|
||||
var callbackInfo = dbInstanceObject._findHandler(mongoReply.responseTo.toString());
|
||||
// If we have an error let's execute the callback and clean up all other
|
||||
// chained commands
|
||||
var firstResult = mongoReply && mongoReply.documents;
|
||||
// Check for an error, if we have one let's trigger the callback and clean up
|
||||
// The chained callbacks
|
||||
if(firstResult[0].err != null || firstResult[0].errmsg != null) {
|
||||
// Trigger the callback for the error
|
||||
dbInstanceObject._callHandler(mongoReply.responseTo, mongoReply, null);
|
||||
} else {
|
||||
var chainedIds = callbackInfo.info.chained;
|
||||
|
||||
if(chainedIds.length > 0 && chainedIds[chainedIds.length - 1] == mongoReply.responseTo) {
|
||||
// Cleanup all other chained calls
|
||||
chainedIds.pop();
|
||||
// Remove listeners
|
||||
for(var i = 0; i < chainedIds.length; i++) dbInstanceObject._removeHandler(chainedIds[i]);
|
||||
// Call the handler
|
||||
dbInstanceObject._callHandler(mongoReply.responseTo, callbackInfo.info.results.shift(), null);
|
||||
} else{
|
||||
// Add the results to all the results
|
||||
for(var i = 0; i < chainedIds.length; i++) {
|
||||
var handler = dbInstanceObject._findHandler(chainedIds[i]);
|
||||
// Check if we have an object, if it's the case take the current object commands and
|
||||
// and add this one
|
||||
if(handler.info != null) {
|
||||
handler.info.results = Array.isArray(callbackInfo.info.results) ? callbackInfo.info.results : [];
|
||||
handler.info.results.push(mongoReply);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} else if(callbackInfo.callback) {
|
||||
// Parse the body
|
||||
mongoReply.parseBody(message, connectionPool.bson, callbackInfo.info.raw, function(err) {
|
||||
// Let's record the stats info if it's enabled
|
||||
if(server.recordQueryStats == true && server._state['runtimeStats'] != null
|
||||
&& server._state.runtimeStats['queryStats'] instanceof RunningStats) {
|
||||
// Add data point to the running statistics object
|
||||
server._state.runtimeStats.queryStats.push(new Date().getTime() - callbackInfo.info.start);
|
||||
}
|
||||
|
||||
// Trigger the callback
|
||||
dbInstanceObject._callHandler(mongoReply.responseTo, mongoReply, null);
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
// Throw error in next tick
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Handle timeout
|
||||
connectionPool.on("timeout", function(err) {
|
||||
// If pool connection is already closed
|
||||
if(server._serverState === 'disconnected') return;
|
||||
// Set server state to disconnected
|
||||
server._serverState = 'disconnected';
|
||||
// // Close the pool
|
||||
// connectionPool.stop();
|
||||
// If we have a callback return the error
|
||||
if(typeof callback === 'function') {
|
||||
// ensure no callbacks get called twice
|
||||
var internalCallback = callback;
|
||||
callback = null;
|
||||
// Perform callback
|
||||
internalCallback(err, null);
|
||||
} else if(server.isSetMember()) {
|
||||
if(server.listeners["timeout"] && server.listeners["timeout"].length > 0) server.emit("timeout", err, server);
|
||||
} else {
|
||||
if(eventReceiver.listeners["timeout"] && eventReceiver.listeners["timeout"].length > 0) eventReceiver.emit("timeout", err, server);
|
||||
}
|
||||
|
||||
// If we are a single server connection fire errors correctly
|
||||
if(!server.isSetMember()) {
|
||||
// Fire all callback errors
|
||||
_fireCallbackErrors(server, err);
|
||||
// Emit error
|
||||
_emitAcrossAllDbInstances(server, eventReceiver, "timeout", err, server);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle errors
|
||||
connectionPool.on("error", function(message) {
|
||||
// If pool connection is already closed
|
||||
if(server._serverState === 'disconnected') return;
|
||||
// Set server state to disconnected
|
||||
server._serverState = 'disconnected';
|
||||
// If we have a callback return the error
|
||||
if(typeof callback === 'function') {// && !server.isSetMember()) {
|
||||
// ensure no callbacks get called twice
|
||||
var internalCallback = callback;
|
||||
callback = null;
|
||||
// Perform callback
|
||||
internalCallback(new Error(message && message.err ? message.err : message), null);
|
||||
} else if(server.isSetMember()) {
|
||||
if(server.listeners["error"] && server.listeners["error"].length > 0) server.emit("error", new Error(message && message.err ? message.err : message), server);
|
||||
} else {
|
||||
if(eventReceiver.listeners["error"] && eventReceiver.listeners["error"].length > 0) eventReceiver.emit("error", new Error(message && message.err ? message.err : message), server);
|
||||
}
|
||||
|
||||
// If we are a single server connection fire errors correctly
|
||||
if(!server.isSetMember()) {
|
||||
// Fire all callback errors
|
||||
_fireCallbackErrors(server, new Error(message && message.err ? message.err : message));
|
||||
// Emit error
|
||||
_emitAcrossAllDbInstances(server, eventReceiver, "error", new Error(message && message.err ? message.err : message), server);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle close events
|
||||
connectionPool.on("close", function() {
|
||||
// If pool connection is already closed
|
||||
if(server._serverState === 'disconnected') return;
|
||||
// Set server state to disconnected
|
||||
server._serverState = 'disconnected';
|
||||
// // Close the pool
|
||||
// connectionPool.stop(true);
|
||||
// If we have a callback return the error
|
||||
if(typeof callback == 'function') {
|
||||
// ensure no callbacks get called twice
|
||||
var internalCallback = callback;
|
||||
callback = null;
|
||||
// Perform callback
|
||||
internalCallback(new Error("connection closed"), null);
|
||||
} else if(server.isSetMember()) {
|
||||
if(server.listeners["close"] && server.listeners["close"].length > 0) server.emit("close", new Error("connection closed"), server);
|
||||
} else {
|
||||
if(eventReceiver.listeners["close"] && eventReceiver.listeners["close"].length > 0) eventReceiver.emit("close", new Error("connection closed"), server);
|
||||
}
|
||||
|
||||
// If we are a single server connection fire errors correctly
|
||||
if(!server.isSetMember()) {
|
||||
// Fire all callback errors
|
||||
_fireCallbackErrors(server, new Error("connection closed"));
|
||||
// Emit error
|
||||
_emitAcrossAllDbInstances(server, eventReceiver, "close", server);
|
||||
}
|
||||
});
|
||||
|
||||
// If we have a parser error we are in an unknown state, close everything and emit
|
||||
// error
|
||||
connectionPool.on("parseError", function(message) {
|
||||
// If pool connection is already closed
|
||||
if(server._serverState === 'disconnected') return;
|
||||
// Set server state to disconnected
|
||||
server._serverState = 'disconnected';
|
||||
// // Close the pool
|
||||
// connectionPool.stop();
|
||||
// If we have a callback return the error
|
||||
if(typeof callback === 'function') {
|
||||
// ensure no callbacks get called twice
|
||||
var internalCallback = callback;
|
||||
callback = null;
|
||||
// Perform callback
|
||||
internalCallback(new Error("connection closed due to parseError"), null);
|
||||
} else if(server.isSetMember()) {
|
||||
if(server.listeners["parseError"] && server.listeners["parseError"].length > 0) server.emit("parseError", new Error("connection closed due to parseError"), server);
|
||||
} else {
|
||||
if(eventReceiver.listeners["parseError"] && eventReceiver.listeners["parseError"].length > 0) eventReceiver.emit("parseError", new Error("connection closed due to parseError"), server);
|
||||
}
|
||||
|
||||
// If we are a single server connection fire errors correctly
|
||||
if(!server.isSetMember()) {
|
||||
// Fire all callback errors
|
||||
_fireCallbackErrors(server, new Error("connection closed due to parseError"));
|
||||
// Emit error
|
||||
_emitAcrossAllDbInstances(server, eventReceiver, "parseError", server);
|
||||
}
|
||||
});
|
||||
|
||||
// Boot up connection poole, pass in a locator of callbacks
|
||||
connectionPool.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire all the errors
|
||||
* @ignore
|
||||
*/
|
||||
var _fireCallbackErrors = function(server, err) {
|
||||
// Locate all the possible callbacks that need to return
|
||||
for(var i = 0; i < server.dbInstances.length; i++) {
|
||||
// Fetch the db Instance
|
||||
var dbInstance = server.dbInstances[i];
|
||||
// Check all callbacks
|
||||
var keys = Object.keys(dbInstance._callBackStore._notReplied);
|
||||
// For each key check if it's a callback that needs to be returned
|
||||
for(var j = 0; j < keys.length; j++) {
|
||||
var info = dbInstance._callBackStore._notReplied[keys[j]];
|
||||
// Check if we have a chained command (findAndModify)
|
||||
if(info && info['chained'] && Array.isArray(info['chained']) && info['chained'].length > 0) {
|
||||
var chained = info['chained'];
|
||||
// Only callback once and the last one is the right one
|
||||
var finalCallback = chained.pop();
|
||||
// console.dir(finalCallback)
|
||||
if(info.connection.socketOptions.host === server.host && info.connection.socketOptions.port === server.port) {
|
||||
dbInstance._callBackStore.emit(finalCallback, err, null);
|
||||
}
|
||||
|
||||
// Put back the final callback to ensure we don't call all commands in the chain
|
||||
chained.push(finalCallback);
|
||||
|
||||
// Remove all chained callbacks
|
||||
for(var i = 0; i < chained.length; i++) {
|
||||
delete dbInstance._callBackStore._notReplied[chained[i]];
|
||||
}
|
||||
} else {
|
||||
if(info && info.connection.socketOptions.host === server.host && info.connection.socketOptions.port === server.port) {
|
||||
dbInstance._callBackStore.emit(keys[j], err, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
var _emitAcrossAllDbInstances = function(server, filterDb, event, message, object) {
|
||||
// Emit close event across all db instances sharing the sockets
|
||||
var allServerInstances = server.allServerInstances();
|
||||
// Fetch the first server instance
|
||||
var serverInstance = allServerInstances[0];
|
||||
// For all db instances signal all db instances
|
||||
if(Array.isArray(serverInstance.dbInstances) && serverInstance.dbInstances.length > 1) {
|
||||
for(var i = 0; i < serverInstance.dbInstances.length; i++) {
|
||||
var dbInstance = serverInstance.dbInstances[i];
|
||||
// Check if it's our current db instance and skip if it is
|
||||
if(filterDb == null || filterDb.databaseName !== dbInstance.databaseName || filterDb.tag !== dbInstance.tag) {
|
||||
dbInstance.emit(event, message, object);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.allRawConnections = function() {
|
||||
return this.connectionPool.getAllConnections();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a writer can be provided
|
||||
* @ignore
|
||||
*/
|
||||
var canCheckoutWriter = function(self, read) {
|
||||
// We cannot write to an arbiter or secondary server
|
||||
if(self.isMasterDoc['arbiterOnly'] == true) {
|
||||
return new Error("Cannot write to an arbiter");
|
||||
} if(self.isMasterDoc['secondary'] == true) {
|
||||
return new Error("Cannot write to a secondary");
|
||||
} else if(read == true && self._readPreference == Server.READ_SECONDARY_ONLY && self.isMasterDoc['ismaster'] == true) {
|
||||
return new Error("Cannot read from primary when secondary only specified");
|
||||
}
|
||||
|
||||
// Return no error
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.checkoutWriter = function(read) {
|
||||
if(read == true) return this.connectionPool.checkoutConnection();
|
||||
// Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
|
||||
var result = canCheckoutWriter(this, read);
|
||||
// If the result is null check out a writer
|
||||
if(result == null) {
|
||||
return this.connectionPool.checkoutConnection();
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a reader can be provided
|
||||
* @ignore
|
||||
*/
|
||||
var canCheckoutReader = function(self) {
|
||||
// We cannot write to an arbiter or secondary server
|
||||
if(self.isMasterDoc['arbiterOnly'] == true) {
|
||||
return new Error("Cannot write to an arbiter");
|
||||
} else if(self._readPreference != null) {
|
||||
// If the read preference is Primary and the instance is not a master return an error
|
||||
if(self._readPreference == Server.READ_PRIMARY && self.isMasterDoc['ismaster'] != true) {
|
||||
return new Error("Read preference is " + Server.READ_PRIMARY + " and server is not master");
|
||||
} else if(self._readPreference == Server.READ_SECONDARY_ONLY && self.isMasterDoc['ismaster'] == true) {
|
||||
return new Error("Cannot read from primary when secondary only specified");
|
||||
}
|
||||
}
|
||||
|
||||
// Return no error
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.checkoutReader = function() {
|
||||
// Check if are allowed to do a checkout (if we try to use an arbiter f.ex)
|
||||
var result = canCheckoutReader(this);
|
||||
// If the result is null check out a writer
|
||||
if(result == null) {
|
||||
return this.connectionPool.checkoutConnection();
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Server.prototype.enableRecordQueryStats = function(enable) {
|
||||
this.recordQueryStats = enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal statistics object used for calculating average and standard devitation on
|
||||
* running queries
|
||||
* @ignore
|
||||
*/
|
||||
var RunningStats = function() {
|
||||
var self = this;
|
||||
this.m_n = 0;
|
||||
this.m_oldM = 0.0;
|
||||
this.m_oldS = 0.0;
|
||||
this.m_newM = 0.0;
|
||||
this.m_newS = 0.0;
|
||||
|
||||
// Define getters
|
||||
Object.defineProperty(this, "numDataValues", { enumerable: true
|
||||
, get: function () { return this.m_n; }
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "mean", { enumerable: true
|
||||
, get: function () { return (this.m_n > 0) ? this.m_newM : 0.0; }
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "variance", { enumerable: true
|
||||
, get: function () { return ((this.m_n > 1) ? this.m_newS/(this.m_n - 1) : 0.0); }
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "standardDeviation", { enumerable: true
|
||||
, get: function () { return Math.sqrt(this.variance); }
|
||||
});
|
||||
|
||||
Object.defineProperty(this, "sScore", { enumerable: true
|
||||
, get: function () {
|
||||
var bottom = this.mean + this.standardDeviation;
|
||||
if(bottom == 0) return 0;
|
||||
return ((2 * this.mean * this.standardDeviation)/(bottom));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
RunningStats.prototype.push = function(x) {
|
||||
// Update the number of samples
|
||||
this.m_n = this.m_n + 1;
|
||||
// See Knuth TAOCP vol 2, 3rd edition, page 232
|
||||
if(this.m_n == 1) {
|
||||
this.m_oldM = this.m_newM = x;
|
||||
this.m_oldS = 0.0;
|
||||
} else {
|
||||
this.m_newM = this.m_oldM + (x - this.m_oldM) / this.m_n;
|
||||
this.m_newS = this.m_oldS + (x - this.m_oldM) * (x - this.m_newM);
|
||||
|
||||
// set up for next iteration
|
||||
this.m_oldM = this.m_newM;
|
||||
this.m_oldS = this.m_newS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "autoReconnect", { enumerable: true
|
||||
, get: function () {
|
||||
return this.options['auto_reconnect'] == null ? false : this.options['auto_reconnect'];
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "connection", { enumerable: true
|
||||
, get: function () {
|
||||
return this.internalConnection;
|
||||
}
|
||||
, set: function(connection) {
|
||||
this.internalConnection = connection;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "master", { enumerable: true
|
||||
, get: function () {
|
||||
return this.internalMaster;
|
||||
}
|
||||
, set: function(value) {
|
||||
this.internalMaster = value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "primary", { enumerable: true
|
||||
, get: function () {
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Getter for query Stats
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "queryStats", { enumerable: true
|
||||
, get: function () {
|
||||
return this._state.runtimeStats.queryStats;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "runtimeStats", { enumerable: true
|
||||
, get: function () {
|
||||
return this._state.runtimeStats;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get Read Preference method
|
||||
* @ignore
|
||||
*/
|
||||
Object.defineProperty(Server.prototype, "readPreference", { enumerable: true
|
||||
, get: function () {
|
||||
if(this._readPreference == null && this.readSecondary) {
|
||||
return Server.READ_SECONDARY;
|
||||
} else if(this._readPreference == null && !this.readSecondary) {
|
||||
return Server.READ_PRIMARY;
|
||||
} else {
|
||||
return this._readPreference;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
exports.Server = Server;
|
||||
125
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/strategies/ping_strategy.js
generated
vendored
Normal file
125
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/strategies/ping_strategy.js
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
var Server = require("../server").Server;
|
||||
|
||||
// The ping strategy uses pings each server and records the
|
||||
// elapsed time for the server so it can pick a server based on lowest
|
||||
// return time for the db command {ping:true}
|
||||
var PingStrategy = exports.PingStrategy = function(replicaset) {
|
||||
this.replicaset = replicaset;
|
||||
this.state = 'disconnected';
|
||||
// Class instance
|
||||
this.Db = require("../../db").Db;
|
||||
}
|
||||
|
||||
// Starts any needed code
|
||||
PingStrategy.prototype.start = function(callback) {
|
||||
this.state = 'connected';
|
||||
// Start ping server
|
||||
this._pingServer(callback);
|
||||
}
|
||||
|
||||
// Stops and kills any processes running
|
||||
PingStrategy.prototype.stop = function(callback) {
|
||||
// Stop the ping process
|
||||
this.state = 'disconnected';
|
||||
// Call the callback
|
||||
callback(null, null);
|
||||
}
|
||||
|
||||
PingStrategy.prototype.checkoutSecondary = function() {
|
||||
// Get all secondary server keys
|
||||
var keys = Object.keys(this.replicaset._state.secondaries);
|
||||
// Contains the picked instance
|
||||
var minimumPingMs = null;
|
||||
var selectedInstance = null;
|
||||
// Pick server key by the lowest ping time
|
||||
for(var i = 0; i < keys.length; i++) {
|
||||
// Fetch a server
|
||||
var server = this.replicaset._state.secondaries[keys[i]];
|
||||
// If we don't have a ping time use it
|
||||
if(server.runtimeStats['pingMs'] == null) {
|
||||
// Set to 0 ms for the start
|
||||
server.runtimeStats['pingMs'] = 0;
|
||||
// Pick server
|
||||
selectedInstance = server;
|
||||
break;
|
||||
} else {
|
||||
// If the next server's ping time is less than the current one choose than one
|
||||
if(minimumPingMs == null || server.runtimeStats['pingMs'] < minimumPingMs) {
|
||||
minimumPingMs = server.runtimeStats['pingMs'];
|
||||
selectedInstance = server;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the selected instance
|
||||
return selectedInstance != null ? selectedInstance.checkoutReader() : null;
|
||||
}
|
||||
|
||||
PingStrategy.prototype._pingServer = function(callback) {
|
||||
var self = this;
|
||||
|
||||
// Ping server function
|
||||
var pingFunction = function() {
|
||||
if(self.state == 'disconnected') return;
|
||||
var addresses = self.replicaset._state != null && self.replicaset._state.addresses != null ? self.replicaset._state.addresses : null;
|
||||
// Grab all servers
|
||||
var serverKeys = Object.keys(addresses);
|
||||
// Number of server entries
|
||||
var numberOfEntries = serverKeys.length;
|
||||
// We got keys
|
||||
for(var i = 0; i < serverKeys.length; i++) {
|
||||
// We got a server instance
|
||||
var server = addresses[serverKeys[i]];
|
||||
// Create a new server object, avoid using internal connections as they might
|
||||
// be in an illegal state
|
||||
new function(serverInstance) {
|
||||
var server = new Server(serverInstance.host, serverInstance.port, {poolSize:1, timeout:500});
|
||||
var db = new self.Db(self.replicaset.db.databaseName, server);
|
||||
// Add error listener
|
||||
db.on("error", function(err) {
|
||||
// Adjust the number of checks
|
||||
numberOfEntries = numberOfEntries - 1;
|
||||
// Close connection
|
||||
db.close();
|
||||
// If we are done with all results coming back trigger ping again
|
||||
if(numberOfEntries == 0 && self.state == 'connected') {
|
||||
setTimeout(pingFunction, 1000);
|
||||
}
|
||||
})
|
||||
|
||||
// Open the db instance
|
||||
db.open(function(err, p_db) {
|
||||
if(err != null) {
|
||||
db.close();
|
||||
} else {
|
||||
// Startup time of the command
|
||||
var startTime = new Date().getTime();
|
||||
// Execute ping on this connection
|
||||
p_db.executeDbCommand({ping:1}, function(err, result) {
|
||||
// Adjust the number of checks
|
||||
numberOfEntries = numberOfEntries - 1;
|
||||
// Get end time of the command
|
||||
var endTime = new Date().getTime();
|
||||
// Store the ping time in the server instance state variable, if there is one
|
||||
if(serverInstance != null && serverInstance.runtimeStats != null && serverInstance.isConnected()) {
|
||||
serverInstance.runtimeStats['pingMs'] = (endTime - startTime);
|
||||
}
|
||||
|
||||
// Close server
|
||||
p_db.close();
|
||||
// If we are done with all results coming back trigger ping again
|
||||
if(numberOfEntries == 0 && self.state == 'connected') {
|
||||
setTimeout(pingFunction, 1000);
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}(server);
|
||||
}
|
||||
}
|
||||
|
||||
// Start pingFunction
|
||||
setTimeout(pingFunction, 1000);
|
||||
// Do the callback
|
||||
callback(null);
|
||||
}
|
||||
40
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/strategies/statistics_strategy.js
generated
vendored
Normal file
40
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/connection/strategies/statistics_strategy.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
// The Statistics strategy uses the measure of each end-start time for each
|
||||
// query executed against the db to calculate the mean, variance and standard deviation
|
||||
// and pick the server which the lowest mean and deviation
|
||||
var StatisticsStrategy = exports.StatisticsStrategy = function(replicaset) {
|
||||
this.replicaset = replicaset;
|
||||
}
|
||||
|
||||
// Starts any needed code
|
||||
StatisticsStrategy.prototype.start = function(callback) {
|
||||
callback(null, null);
|
||||
}
|
||||
|
||||
StatisticsStrategy.prototype.stop = function(callback) {
|
||||
// Remove reference to replicaset
|
||||
this.replicaset = null;
|
||||
// Perform callback
|
||||
callback(null, null);
|
||||
}
|
||||
|
||||
StatisticsStrategy.prototype.checkoutSecondary = function() {
|
||||
// Get all secondary server keys
|
||||
var keys = Object.keys(this.replicaset._state.secondaries);
|
||||
// Contains the picked instance
|
||||
var minimumSscore = null;
|
||||
var selectedInstance = null;
|
||||
|
||||
// Pick server key by the lowest ping time
|
||||
for(var i = 0; i < keys.length; i++) {
|
||||
// Fetch a server
|
||||
var server = this.replicaset._state.secondaries[keys[i]];
|
||||
// Pick server by lowest Sscore
|
||||
if(minimumSscore == null || (server.queryStats.sScore < minimumSscore)) {
|
||||
minimumSscore = server.queryStats.sScore;
|
||||
selectedInstance = server;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the selected instance
|
||||
return selectedInstance != null ? selectedInstance.checkoutReader() : null;
|
||||
}
|
||||
729
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/cursor.js
generated
vendored
Normal file
729
app/node_modules/mongoskin/node_modules/mongodb/lib/mongodb/cursor.js
generated
vendored
Normal file
@@ -0,0 +1,729 @@
|
||||
var QueryCommand = require('./commands/query_command').QueryCommand,
|
||||
GetMoreCommand = require('./commands/get_more_command').GetMoreCommand,
|
||||
KillCursorCommand = require('./commands/kill_cursor_command').KillCursorCommand,
|
||||
Long = require('bson').Long,
|
||||
CursorStream = require('./cursorstream'),
|
||||
utils = require('./utils');
|
||||
|
||||
/**
|
||||
* Constructor for a cursor object that handles all the operations on query result
|
||||
* using find. This cursor object is unidirectional and cannot traverse backwards. Clients should not be creating a cursor directly,
|
||||
* but use find to acquire a cursor.
|
||||
*
|
||||
* @class Represents a Cursor.
|
||||
* @param {Db} db the database object to work with.
|
||||
* @param {Collection} collection the collection to query.
|
||||
* @param {Object} selector the query selector.
|
||||
* @param {Object} fields an object containing what fields to include or exclude from objects returned.
|
||||
* @param {Number} skip number of documents to skip.
|
||||
* @param {Number} limit the number of results to return. -1 has a special meaning and is used by Db.eval. A value of 1 will also be treated as if it were -1.
|
||||
* @param {String|Array|Object} sort the required sorting for the query.
|
||||
* @param {Object} hint force the query to use a specific index.
|
||||
* @param {Boolean} explain return the explaination of the query.
|
||||
* @param {Boolean} snapshot Snapshot mode assures no duplicates are returned.
|
||||
* @param {Boolean} timeout allow the query to timeout.
|
||||
* @param {Boolean} tailable allow the cursor to be tailable.
|
||||
* @param {Number} batchSize the number of the subset of results to request the database to return for every request. This should initially be greater than 1 otherwise the database will automatically close the cursor. The batch size can be set to 1 with cursorInstance.batchSize after performing the initial query to the database.
|
||||
* @param {Boolean} raw return all query documents as raw buffers (default false).
|
||||
* @param {Boolean} read specify override of read from source (primary/secondary).
|
||||
* @param {Boolean} returnKey only return the index key.
|
||||
* @param {Number} maxScan limit the number of items to scan.
|
||||
* @param {Number} min set index bounds.
|
||||
* @param {Number} max set index bounds.
|
||||
* @param {Boolean} showDiskLoc show disk location of results.
|
||||
* @param {String} comment you can put a $comment field on a query to make looking in the profiler logs simpler.
|
||||
*/
|
||||
function Cursor(db, collection, selector, fields, skip, limit
|
||||
, sort, hint, explain, snapshot, timeout, tailable, batchSize, slaveOk, raw, read
|
||||
, returnKey, maxScan, min, max, showDiskLoc, comment) {
|
||||
this.db = db;
|
||||
this.collection = collection;
|
||||
this.selector = selector;
|
||||
this.fields = fields;
|
||||
this.skipValue = skip == null ? 0 : skip;
|
||||
this.limitValue = limit == null ? 0 : limit;
|
||||
this.sortValue = sort;
|
||||
this.hint = hint;
|
||||
this.explainValue = explain;
|
||||
this.snapshot = snapshot;
|
||||
this.timeout = timeout == null ? true : timeout;
|
||||
this.tailable = tailable;
|
||||
this.batchSizeValue = batchSize == null ? 0 : batchSize;
|
||||
this.slaveOk = slaveOk == null ? collection.slaveOk : slaveOk;
|
||||
this.raw = raw == null ? false : raw;
|
||||
this.read = read == null ? true : read;
|
||||
this.returnKey = returnKey;
|
||||
this.maxScan = maxScan;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.showDiskLoc = showDiskLoc;
|
||||
this.comment = comment;
|
||||
|
||||
this.totalNumberOfRecords = 0;
|
||||
this.items = [];
|
||||
this.cursorId = Long.fromInt(0);
|
||||
|
||||
// State variables for the cursor
|
||||
this.state = Cursor.INIT;
|
||||
// Keep track of the current query run
|
||||
this.queryRun = false;
|
||||
this.getMoreTimer = false;
|
||||
this.collectionName = (this.db.databaseName ? this.db.databaseName + "." : '') + this.collection.collectionName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets this cursor to its initial state. All settings like the query string,
|
||||
* tailable, batchSizeValue, skipValue and limits are preserved.
|
||||
*
|
||||
* @return {Cursor} returns itself with rewind applied.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.rewind = function() {
|
||||
var self = this;
|
||||
|
||||
if (self.state != Cursor.INIT) {
|
||||
if (self.state != Cursor.CLOSED) {
|
||||
self.close(function() {});
|
||||
}
|
||||
|
||||
self.numberOfReturned = 0;
|
||||
self.totalNumberOfRecords = 0;
|
||||
self.items = [];
|
||||
self.cursorId = Long.fromInt(0);
|
||||
self.state = Cursor.INIT;
|
||||
self.queryRun = false;
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Returns an array of documents. The caller is responsible for making sure that there
|
||||
* is enough memory to store the results. Note that the array only contain partial
|
||||
* results when this cursor had been previouly accessed. In that case,
|
||||
* cursor.rewind() can be used to reset the cursor.
|
||||
*
|
||||
* @param {Function} callback This will be called after executing this method successfully. The first paramter will contain the Error object if an error occured, or null otherwise. The second paramter will contain an array of BSON deserialized objects as a result of the query.
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.toArray = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if(!callback) {
|
||||
throw new Error('callback is mandatory');
|
||||
}
|
||||
|
||||
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(err != null) return callback(err, null);
|
||||
|
||||
if (item != null) {
|
||||
items.push(item);
|
||||
} else {
|
||||
var resultItems = items;
|
||||
items = null;
|
||||
self.items = [];
|
||||
// Returns items
|
||||
callback(err, resultItems);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback(new Error("Cursor is closed"), null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterates over all the documents for this cursor. As with **{cursor.toArray}**,
|
||||
* not all of the elements will be iterated if this cursor had been previouly accessed.
|
||||
* In that case, **{cursor.rewind}** can be used to reset the cursor. However, unlike
|
||||
* **{cursor.toArray}**, the cursor will only hold a maximum of batch size elements
|
||||
* at any given time if batch size is specified. Otherwise, the caller is responsible
|
||||
* for making sure that the entire result can fit the memory.
|
||||
*
|
||||
* @param {Function} callback this will be called for while iterating every document of the query result. The first paramter will contain the Error object if an error occured, or null otherwise. While the second paramter will contain the document.
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.each = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if (!callback) {
|
||||
throw new Error('callback is mandatory');
|
||||
}
|
||||
|
||||
if(this.state != Cursor.CLOSED) {
|
||||
//FIX: stack overflow (on deep callback) (cred: https://github.com/limp/node-mongodb-native/commit/27da7e4b2af02035847f262b29837a94bbbf6ce2)
|
||||
process.nextTick(function(){
|
||||
var s = new Date()
|
||||
// Fetch the next object until there is no more objects
|
||||
self.nextObject(function(err, item) {
|
||||
if(err != null) return callback(err, null);
|
||||
if(item != null) {
|
||||
callback(null, item);
|
||||
self.each(callback);
|
||||
} else {
|
||||
// Close the cursor if done
|
||||
self.state = Cursor.CLOSED;
|
||||
callback(err, null);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
callback(new Error("Cursor is closed"), null);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Determines how many result the query for this cursor will return
|
||||
*
|
||||
* @param {Function} callback this will be after executing this method. The first paramter will contain the Error object if an error occured, or null otherwise. While the second paramter will contain the number of results or null if an error occured.
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.count = function(callback) {
|
||||
this.collection.count(this.selector, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the sort parameter of this cursor to the given value.
|
||||
*
|
||||
* This method has the following method signatures:
|
||||
* (keyOrList, callback)
|
||||
* (keyOrList, direction, callback)
|
||||
*
|
||||
* @param {String|Array|Object} keyOrList This can be a string or an array. If passed as a string, the string will be the field to sort. If passed an array, each element will represent a field to be sorted and should be an array that contains the format [string, direction].
|
||||
* @param {String|Number} direction this determines how the results are sorted. "asc", "ascending" or 1 for asceding order while "desc", "desceding or -1 for descending order. Note that the strings are case insensitive.
|
||||
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
|
||||
* @return {Cursor} an instance of this object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.sort = function(keyOrList, direction, callback) {
|
||||
callback = callback || function(){};
|
||||
if(typeof direction === "function") { callback = direction; direction = null; }
|
||||
|
||||
if(this.tailable) {
|
||||
callback(new Error("Tailable cursor doesn't support sorting"), null);
|
||||
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
|
||||
callback(new Error("Cursor is closed"), null);
|
||||
} else {
|
||||
var order = keyOrList;
|
||||
|
||||
if(direction != null) {
|
||||
order = [[keyOrList, direction]];
|
||||
}
|
||||
|
||||
this.sortValue = order;
|
||||
callback(null, this);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the limit parameter of this cursor to the given value.
|
||||
*
|
||||
* @param {Number} limit the new limit.
|
||||
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the limit given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
|
||||
* @return {Cursor} an instance of this object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.limit = function(limit, callback) {
|
||||
if(this.tailable) {
|
||||
if(callback) {
|
||||
callback(new Error("Tailable cursor doesn't support limit"), null);
|
||||
} else {
|
||||
throw new Error("Tailable cursor doesn't support limit");
|
||||
}
|
||||
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
|
||||
if(callback) {
|
||||
callback(new Error("Cursor is closed"), null);
|
||||
} else {
|
||||
throw new Error("Cursor is closed");
|
||||
}
|
||||
} else {
|
||||
if(limit != null && limit.constructor != Number) {
|
||||
if(callback) {
|
||||
callback(new Error("limit requires an integer"), null);
|
||||
} else {
|
||||
throw new Error("limit requires an integer");
|
||||
}
|
||||
} else {
|
||||
this.limitValue = limit;
|
||||
if(callback) return callback(null, this);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the skip parameter of this cursor to the given value.
|
||||
*
|
||||
* @param {Number} skip the new skip value.
|
||||
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the skip value given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
|
||||
* @return {Cursor} an instance of this object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.skip = function(skip, callback) {
|
||||
callback = callback || function(){};
|
||||
|
||||
if(this.tailable) {
|
||||
callback(new Error("Tailable cursor doesn't support skip"), null);
|
||||
} else if(this.queryRun == true || this.state == Cursor.CLOSED) {
|
||||
callback(new Error("Cursor is closed"), null);
|
||||
} else {
|
||||
if(skip != null && skip.constructor != Number) {
|
||||
callback(new Error("skip requires an integer"), null);
|
||||
} else {
|
||||
this.skipValue = skip;
|
||||
callback(null, this);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the batch size parameter of this cursor to the given value.
|
||||
*
|
||||
* @param {Number} batchSize the new batch size.
|
||||
* @param {Function} [callback] this optional callback will be called after executing this method. The first parameter will contain an error object when the batchSize given is not a valid number or when the cursor is already closed while the second parameter will contain a reference to this object upon successful execution.
|
||||
* @return {Cursor} an instance of this object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.batchSize = function(batchSize, callback) {
|
||||
if(this.state == Cursor.CLOSED) {
|
||||
if(callback != null) {
|
||||
return callback(new Error("Cursor is closed"), null);
|
||||
} else {
|
||||
throw new Error("Cursor is closed");
|
||||
}
|
||||
} else if(batchSize != null && batchSize.constructor != Number) {
|
||||
if(callback != null) {
|
||||
return callback(new Error("batchSize requires an integer"), null);
|
||||
} else {
|
||||
throw new Error("batchSize requires an integer");
|
||||
}
|
||||
} else {
|
||||
this.batchSizeValue = batchSize;
|
||||
if(callback != null) return callback(null, this);
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* The limit used for the getMore command
|
||||
*
|
||||
* @return {Number} The number of records to request per batch.
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
var limitRequest = function(self) {
|
||||
var requestedLimit = self.limitValue;
|
||||
var absLimitValue = Math.abs(self.limitValue);
|
||||
var absBatchValue = Math.abs(self.batchSizeValue);
|
||||
|
||||
if(absLimitValue > 0) {
|
||||
if (absBatchValue > 0) {
|
||||
requestedLimit = Math.min(absLimitValue, absBatchValue);
|
||||
}
|
||||
} else {
|
||||
requestedLimit = self.batchSizeValue;
|
||||
}
|
||||
|
||||
return requestedLimit;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates a QueryCommand object using the parameters of this cursor.
|
||||
*
|
||||
* @return {QueryCommand} The command object
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
var generateQueryCommand = function(self) {
|
||||
// Unpack the options
|
||||
var queryOptions = QueryCommand.OPTS_NONE;
|
||||
if(!self.timeout) {
|
||||
queryOptions |= QueryCommand.OPTS_NO_CURSOR_TIMEOUT;
|
||||
}
|
||||
|
||||
if(self.tailable != null) {
|
||||
queryOptions |= QueryCommand.OPTS_TAILABLE_CURSOR;
|
||||
self.skipValue = self.limitValue = 0;
|
||||
}
|
||||
|
||||
if(self.slaveOk) {
|
||||
queryOptions |= QueryCommand.OPTS_SLAVE;
|
||||
}
|
||||
|
||||
// limitValue of -1 is a special case used by Db#eval
|
||||
var numberToReturn = self.limitValue == -1 ? -1 : limitRequest(self);
|
||||
|
||||
// Check if we need a special selector
|
||||
if(self.sortValue != null || self.explainValue != null || self.hint != null || self.snapshot != null
|
||||
|| self.returnKey != null || self.maxScan != null || self.min != null || self.max != null
|
||||
|| self.showDiskLoc != null || self.comment != null) {
|
||||
|
||||
// Build special selector
|
||||
var specialSelector = {'query':self.selector};
|
||||
if(self.sortValue != null) specialSelector['orderby'] = utils.formattedOrderClause(self.sortValue);
|
||||
if(self.hint != null && self.hint.constructor == Object) specialSelector['$hint'] = self.hint;
|
||||
if(self.explainValue != null) specialSelector['$explain'] = true;
|
||||
if(self.snapshot != null) specialSelector['$snapshot'] = true;
|
||||
if(self.returnKey != null) specialSelector['$returnKey'] = self.returnKey;
|
||||
if(self.maxScan != null) specialSelector['$maxScan'] = self.maxScan;
|
||||
if(self.min != null) specialSelector['$min'] = self.min;
|
||||
if(self.max != null) specialSelector['$max'] = self.max;
|
||||
if(self.showDiskLoc != null) specialSelector['$showDiskLoc'] = self.showDiskLoc;
|
||||
if(self.comment != null) specialSelector['$comment'] = self.comment;
|
||||
|
||||
// Return the query
|
||||
return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, specialSelector, self.fields);
|
||||
} else {
|
||||
return new QueryCommand(self.db, self.collectionName, queryOptions, self.skipValue, numberToReturn, self.selector, self.fields);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @return {Object} Returns an object containing the sort value of this cursor with
|
||||
* the proper formatting that can be used internally in this cursor.
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
Cursor.prototype.formattedOrderClause = function() {
|
||||
return utils.formattedOrderClause(this.sortValue);
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts the value of the sort direction into its equivalent numerical value.
|
||||
*
|
||||
* @param sortDirection {String|number} Range of acceptable values:
|
||||
* 'ascending', 'descending', 'asc', 'desc', 1, -1
|
||||
*
|
||||
* @return {number} The equivalent numerical value
|
||||
* @throws Error if the given sortDirection is invalid
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
Cursor.prototype.formatSortValue = function(sortDirection) {
|
||||
return utils.formatSortValue(sortDirection);
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the next document from the cursor.
|
||||
*
|
||||
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.nextObject = function(callback) {
|
||||
var self = this;
|
||||
|
||||
if(self.state == Cursor.INIT) {
|
||||
var cmd;
|
||||
try {
|
||||
cmd = generateQueryCommand(self);
|
||||
} catch (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
var commandHandler = function(err, result) {
|
||||
if(err != null && result == null) return callback(err, null);
|
||||
|
||||
if(!err && result.documents[0] && result.documents[0]['$err']) {
|
||||
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, using forloop to avoid
|
||||
// new array allocations and copying
|
||||
for(var i = 0; i < result.documents.length; i++) {
|
||||
self.items.push(result.documents[i]);
|
||||
}
|
||||
|
||||
result = null;
|
||||
self.nextObject(callback);
|
||||
};
|
||||
|
||||
self.db._executeQueryCommand(cmd, {read:self.read, raw:self.raw}, commandHandler);
|
||||
commandHandler = null;
|
||||
} else if(self.items.length) {
|
||||
callback(null, self.items.shift());
|
||||
} else if(self.cursorId.greaterThan(Long.fromInt(0))) {
|
||||
getMore(self, callback);
|
||||
} else {
|
||||
// Force cursor to stay open
|
||||
return self.close(function() {callback(null, null);});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets more results from the database if any.
|
||||
*
|
||||
* @param {Function} callback this will be called after executing this method. The first parameter will contain an error object on error while the second parameter will contain a document from the returned result or null if there are no more results.
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
var getMore = function(self, callback) {
|
||||
var limit = 0;
|
||||
|
||||
if (!self.tailable && self.limitValue > 0) {
|
||||
limit = self.limitValue - self.totalNumberOfRecords;
|
||||
if (limit < 1) {
|
||||
self.close(function() {callback(null, null);});
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
var getMoreCommand = new GetMoreCommand(
|
||||
self.db
|
||||
, self.collectionName
|
||||
, limitRequest(self)
|
||||
, self.cursorId
|
||||
);
|
||||
|
||||
var options = { read: self.read, raw: self.raw };
|
||||
|
||||
// Execute the command
|
||||
self.db._executeQueryCommand(getMoreCommand, options, function(err, result) {
|
||||
try {
|
||||
if(err != null) callback(err, null);
|
||||
|
||||
var isDead = 1 === result.responseFlag && result.cursorId.isZero();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
self.items = self.items.concat(result.documents);
|
||||
// result = null;
|
||||
callback(null, self.items.shift());
|
||||
} else if(self.tailable && !isDead) {
|
||||
self.getMoreTimer = setTimeout(function() {getMore(self, callback);}, 500);
|
||||
} else {
|
||||
self.close(function() {callback(null, null);});
|
||||
}
|
||||
|
||||
result = null;
|
||||
} catch(err) {
|
||||
callback(err, null);
|
||||
}
|
||||
});
|
||||
|
||||
getMoreCommand = null;
|
||||
} catch(err) {
|
||||
var handleClose = function() {
|
||||
callback(err, null);
|
||||
};
|
||||
|
||||
self.close(handleClose);
|
||||
handleClose = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a detailed information about how the query is performed on this cursor and how
|
||||
* long it took the database to process it.
|
||||
*
|
||||
* @param {Function} callback this will be called after executing this method. The first parameter will always be null while the second parameter will be an object containing the details.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.explain = function(callback) {
|
||||
var limit = (-1)*Math.abs(this.limitValue);
|
||||
// Create a new cursor and fetch the plan
|
||||
var cursor = new Cursor(this.db, this.collection, this.selector, this.fields, this.skipValue, limit,
|
||||
this.sortValue, this.hint, true, this.snapshot, this.timeout, this.tailable, this.batchSizeValue);
|
||||
// Fetch the explaination document
|
||||
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);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a stream object that can be used to listen to and stream records
|
||||
* (**Use the CursorStream object instead as this is deprected**)
|
||||
*
|
||||
* Options
|
||||
* - **fetchSize** {Number} the number of records to fetch in each batch (steam specific batchSize).
|
||||
*
|
||||
* Events
|
||||
* - **data** {function(item) {}} the data event triggers when a document is ready.
|
||||
* - **error** {function(err) {}} the error event triggers if an error happens.
|
||||
* - **end** {function() {}} the end event triggers when there is no more documents available.
|
||||
*
|
||||
* @param {Object} [options] additional options for streamRecords.
|
||||
* @return {EventEmitter} returns a stream object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.streamRecords = function(options) {
|
||||
var args = Array.prototype.slice.call(arguments, 0);
|
||||
options = args.length ? args.shift() : {};
|
||||
|
||||
var
|
||||
self = this,
|
||||
stream = new process.EventEmitter(),
|
||||
recordLimitValue = this.limitValue || 0,
|
||||
emittedRecordCount = 0,
|
||||
queryCommand = generateQueryCommand(self);
|
||||
|
||||
// see http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol
|
||||
queryCommand.numberToReturn = options.fetchSize ? options.fetchSize : 500;
|
||||
// Execute the query
|
||||
execute(queryCommand);
|
||||
|
||||
function execute(command) {
|
||||
self.db._executeQueryCommand(command, {read:self.read, raw:self.raw}, function(err,result) {
|
||||
if(err) {
|
||||
stream.emit('error', err);
|
||||
self.close(function(){});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self.queryRun && result) {
|
||||
self.queryRun = true;
|
||||
self.cursorId = result.cursorId;
|
||||
self.state = Cursor.OPEN;
|
||||
self.getMoreCommand = new GetMoreCommand(self.db, self.collectionName, queryCommand.numberToReturn, result.cursorId);
|
||||
}
|
||||
|
||||
var resflagsMap = {
|
||||
CursorNotFound:1<<0,
|
||||
QueryFailure:1<<1,
|
||||
ShardConfigStale:1<<2,
|
||||
AwaitCapable:1<<3
|
||||
};
|
||||
|
||||
if(result.documents && result.documents.length && !(result.responseFlag & resflagsMap.QueryFailure)) {
|
||||
try {
|
||||
result.documents.forEach(function(doc){
|
||||
if(recordLimitValue && emittedRecordCount>=recordLimitValue) {
|
||||
throw("done");
|
||||
}
|
||||
emittedRecordCount++;
|
||||
stream.emit('data', doc);
|
||||
});
|
||||
} catch(err) {
|
||||
if (err != "done") { throw err; }
|
||||
else {
|
||||
self.close(function(){
|
||||
stream.emit('end', recordLimitValue);
|
||||
});
|
||||
self.close(function(){});
|
||||
return;
|
||||
}
|
||||
}
|
||||
// rinse & repeat
|
||||
execute(self.getMoreCommand);
|
||||
} else {
|
||||
self.close(function(){
|
||||
stream.emit('end', recordLimitValue);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return stream;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a Node ReadStream interface for this cursor.
|
||||
*
|
||||
* @return {CursorStream} returns a stream object.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.stream = function stream () {
|
||||
return new CursorStream(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the cursor.
|
||||
*
|
||||
* @param {Function} callback this will be called after executing this method. The first parameter will always contain null while the second parameter will contain a reference to this cursor.
|
||||
* @return {null}
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.close = function(callback) {
|
||||
var self = this
|
||||
this.getMoreTimer && clearTimeout(this.getMoreTimer);
|
||||
// Close the cursor if not needed
|
||||
if(this.cursorId instanceof Long && this.cursorId.greaterThan(Long.fromInt(0))) {
|
||||
try {
|
||||
var command = new KillCursorCommand(this.db, [this.cursorId]);
|
||||
this.db._executeQueryCommand(command, {read:self.read, raw:self.raw}, null);
|
||||
} catch(err) {}
|
||||
}
|
||||
|
||||
// Reset cursor id
|
||||
this.cursorId = Long.fromInt(0);
|
||||
// Set to closed status
|
||||
this.state = Cursor.CLOSED;
|
||||
|
||||
if(callback) {
|
||||
callback(null, self);
|
||||
self.items = [];
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if the cursor is closed or open.
|
||||
*
|
||||
* @return {Boolean} returns the state of the cursor.
|
||||
* @api public
|
||||
*/
|
||||
Cursor.prototype.isClosed = function() {
|
||||
return this.state == Cursor.CLOSED ? true : false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Init state
|
||||
*
|
||||
* @classconstant INIT
|
||||
**/
|
||||
Cursor.INIT = 0;
|
||||
|
||||
/**
|
||||
* Cursor open
|
||||
*
|
||||
* @classconstant OPEN
|
||||
**/
|
||||
Cursor.OPEN = 1;
|
||||
|
||||
/**
|
||||
* Cursor closed
|
||||
*
|
||||
* @classconstant CLOSED
|
||||
**/
|
||||
Cursor.CLOSED = 2;
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
* @api private
|
||||
*/
|
||||
exports.Cursor = Cursor;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user