Skip to content
This repository has been archived by the owner on Sep 23, 2024. It is now read-only.

Commit

Permalink
Added BSON Regexp class and refactored to have options object instead…
Browse files Browse the repository at this point in the history
… of params
  • Loading branch information
christkv committed Nov 28, 2016
1 parent 5e05a3c commit ef25d9d
Show file tree
Hide file tree
Showing 52 changed files with 8,274 additions and 717 deletions.
343 changes: 260 additions & 83 deletions ext/bson.cc

Large diffs are not rendered by default.

59 changes: 31 additions & 28 deletions ext/bson.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,25 +78,25 @@ inline Local<String> NanKey(const Nan::Persistent<String>& s) {

enum BsonType
{
BSON_TYPE_NUMBER = 1,
BSON_TYPE_STRING = 2,
BSON_TYPE_OBJECT = 3,
BSON_TYPE_ARRAY = 4,
BSON_TYPE_BINARY = 5,
BSON_TYPE_UNDEFINED = 6,
BSON_TYPE_OID = 7,
BSON_TYPE_BOOLEAN = 8,
BSON_TYPE_DATE = 9,
BSON_TYPE_NULL = 10,
BSON_TYPE_REGEXP = 11,
BSON_TYPE_CODE = 13,
BSON_TYPE_SYMBOL = 14,
BSON_TYPE_CODE_W_SCOPE = 15,
BSON_TYPE_INT = 16,
BSON_TYPE_TIMESTAMP = 17,
BSON_TYPE_LONG = 18,
BSON_TYPE_MAX_KEY = 0x7f,
BSON_TYPE_MIN_KEY = 0xff
BSON_TYPE_NUMBER = 1,
BSON_TYPE_STRING = 2,
BSON_TYPE_OBJECT = 3,
BSON_TYPE_ARRAY = 4,
BSON_TYPE_BINARY = 5,
BSON_TYPE_UNDEFINED = 6,
BSON_TYPE_OID = 7,
BSON_TYPE_BOOLEAN = 8,
BSON_TYPE_DATE = 9,
BSON_TYPE_NULL = 10,
BSON_TYPE_REGEXP = 11,
BSON_TYPE_CODE = 13,
BSON_TYPE_SYMBOL = 14,
BSON_TYPE_CODE_W_SCOPE = 15,
BSON_TYPE_INT = 16,
BSON_TYPE_TIMESTAMP = 17,
BSON_TYPE_LONG = 18,
BSON_TYPE_MAX_KEY = 0x7f,
BSON_TYPE_MIN_KEY = 0xff
};

//===========================================================================
Expand Down Expand Up @@ -135,6 +135,7 @@ class BSON : public Nan::ObjectWrap {
Nan::Persistent<Function> objectIDConstructor;
Nan::Persistent<Function> binaryConstructor;
Nan::Persistent<Function> codeConstructor;
Nan::Persistent<Function> regexpConstructor;
Nan::Persistent<Function> dbrefConstructor;
Nan::Persistent<Function> symbolConstructor;
Nan::Persistent<Function> doubleConstructor;
Expand Down Expand Up @@ -352,8 +353,8 @@ template<typename T> class BSONSerializer : public T
typedef T Inherited;

public:
BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions) : Inherited(), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, char* parentParam) : Inherited(parentParam), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), bson(aBson) { }
BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, bool ignoreUndefined) : Inherited(), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), ignoreUndefined(ignoreUndefined), bson(aBson) { }
BSONSerializer(BSON* aBson, bool aCheckKeys, bool aSerializeFunctions, bool ignoreUndefined, char* parentParam) : Inherited(parentParam), checkKeys(aCheckKeys), serializeFunctions(aSerializeFunctions), ignoreUndefined(ignoreUndefined), bson(aBson) { }

void SerializeDocument(const Local<Value>& value);
void SerializeArray(const Local<Value>& value);
Expand All @@ -362,6 +363,7 @@ template<typename T> class BSONSerializer : public T
private:
bool checkKeys;
bool serializeFunctions;
bool ignoreUndefined;
BSON* bson;
};

Expand All @@ -370,10 +372,10 @@ template<typename T> class BSONSerializer : public T
class BSONDeserializer
{
public:
BSONDeserializer(BSON* aBson, char* data, size_t length);
BSONDeserializer(BSONDeserializer& parentSerializer, size_t length);
BSONDeserializer(BSON* aBson, char* data, size_t length, bool bsonRegExp);
BSONDeserializer(BSONDeserializer& parentSerializer, size_t length, bool bsonRegExp);

Local<Value> DeserializeDocument(bool promoteLongs);
Local<Value> DeserializeDocument(bool promoteLongs, bool promoteBuffers);

bool HasMoreData() const { return p < pEnd; }
Local<Value> ReadCString();
Expand Down Expand Up @@ -445,15 +447,16 @@ class BSONDeserializer
size_t GetSerializeSize() const { return p - pStart; }

private:
Local<Value> DeserializeArray(bool promoteLongs);
Local<Value> DeserializeValue(BsonType type, bool promoteLongs);
Local<Value> DeserializeDocumentInternal(bool promoteLongs);
Local<Value> DeserializeArrayInternal(bool promoteLongs);
Local<Value> DeserializeArray(bool promoteLongs, bool promoteBuffers);
Local<Value> DeserializeValue(BsonType type, bool promoteLongs, bool promoteBuffers);
Local<Value> DeserializeDocumentInternal(bool promoteLongs, bool promoteBuffers);
Local<Value> DeserializeArrayInternal(bool promoteLongs, bool promoteBuffers);

BSON* bson;
char* const pStart;
char* p;
char* const pEnd;
bool bsonRegExp;
};

//===========================================================================
Expand Down
1 change: 1 addition & 0 deletions ext/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ try {
bson = require('bindings')('bson.node');
}
} catch(err) {
console.log(err)
// Attempt to load the release bson version
try {
bson = require('bindings')('bson.node');
Expand Down
36 changes: 34 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,18 @@
var BSON = require('./ext').BSON;
var BSON = require('./ext').BSON,
Binary = require('./lib/bson/binary'),
Code = require('./lib/bson/code'),
DBRef = require('./lib/bson/db_ref'),
Decimal128 = require('./lib/bson/decimal128'),
Double = require('./lib/bson/double'),
Int32 = require('./lib/bson/int_32'),
Long = require('./lib/bson/long'),
Map = require('./lib/bson/map'),
MaxKey = require('./lib/bson/max_key'),
MinKey = require('./lib/bson/min_key'),
ObjectId = require('./lib/bson/objectid'),
BSONRegExp = require('./lib/bson/regexp'),
Symbol = require('./lib/bson/symbol'),
Timestamp = require('./lib/bson/timestamp');

// BSON MAX VALUES
BSON.BSON_INT32_MAX = 0x7FFFFFFF;
Expand All @@ -11,4 +25,22 @@ BSON.BSON_INT64_MIN = -Math.pow(2, 63);
BSON.JS_INT_MAX = 0x20000000000000; // Any integer up to 2^53 can be precisely represented by a double.
BSON.JS_INT_MIN = -0x20000000000000; // Any integer down to -2^53 can be precisely represented by a double.

module.exports = BSON;
// Add BSON types to function creation
BSON.Binary = Binary;
BSON.Code = Code;
BSON.DBRef = DBRef;
BSON.Decimal128 = Decimal128;
BSON.Double = Double;
BSON.Int32 = Int32;
BSON.Long = Long;
BSON.Map = Map;
BSON.MaxKey = MaxKey;
BSON.MinKey = MinKey;
BSON.ObjectId = ObjectId;
BSON.ObjectID = ObjectId;
BSON.BSONRegExp = BSONRegExp;
BSON.Symbol = Symbol;
BSON.Timestamp = Timestamp;

// Return the BSON
module.exports = BSON;
10 changes: 5 additions & 5 deletions lib/bson/regexp.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
*/
function BSONRegExp(pattern, options) {
if(!(this instanceof BSONRegExp)) return new BSONRegExp();

// Execute
this._bsontype = 'BSONRegExp';
this.pattern = pattern;
this.options = options;
this.pattern = pattern || '';
this.options = options || '';

// Validate options
for(var i = 0; i < options.length; i++) {
if(!(this.options[i] == 'i'
if(!(this.options[i] == 'i'
|| this.options[i] == 'm'
|| this.options[i] == 'x'
|| this.options[i] == 'l'
Expand All @@ -27,4 +27,4 @@ function BSONRegExp(pattern, options) {
}

module.exports = BSONRegExp;
module.exports.BSONRegExp = BSONRegExp;
module.exports.BSONRegExp = BSONRegExp;
8 changes: 4 additions & 4 deletions test/binary_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ for (var i = 0; i < 64; i++) {

function BinaryParser (bigEndian, allowExceptions) {
if(!(this instanceof BinaryParser)) return new BinaryParser(bigEndian, allowExceptions);

this.bigEndian = bigEndian;
this.allowExceptions = allowExceptions;
};
Expand Down Expand Up @@ -48,7 +48,7 @@ BinaryParser.decodeInt = function decodeInt (data, bits, signed, forceBigEndian)
var b = new this.Buffer(this.bigEndian || forceBigEndian, data)
, x = b.readBits(0, bits)
, max = maxBits[bits]; //max = Math.pow( 2, bits );

return signed && x >= max / 2
? x - max
: x;
Expand Down Expand Up @@ -271,7 +271,7 @@ BinaryParser.hprint = function hprint (s) {
if (s.charCodeAt(i) < 32) {
number = s.charCodeAt(i) <= 15
? "0" + s.charCodeAt(i).toString(16)
: s.charCodeAt(i).toString(16);
: s.charCodeAt(i).toString(16);
process.stdout.write(number + " ")
} else {
number = s.charCodeAt(i) <= 15
Expand All @@ -280,7 +280,7 @@ BinaryParser.hprint = function hprint (s) {
process.stdout.write(number + " ")
}
}

process.stdout.write("\n\n");
};

Expand Down
140 changes: 140 additions & 0 deletions test/node/bson_compliance_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
var BSON = require('../..'),
Code = BSON.Code,
Binary = BSON.Binary,
Timestamp = BSON.Timestamp,
Long = BSON.Long,
MongoReply = BSON.MongoReply,
ObjectID = BSON.ObjectID,
ObjectId = BSON.ObjectID,
Symbol = BSON.Symbol,
DBRef = BSON.DBRef,
Int32 = BSON.Int32,
BSONRegExp = BSON.BSONRegExp,
Decimal128 = BSON.Decimal128,
Double = BSON.Double,
MinKey = BSON.MinKey,
MaxKey = BSON.MaxKey,
fs = require('fs');

console.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!")
console.dir(BSON)

/**
* Retrieve the server information for the current
* instance of the db client
*
* @ignore
*/
exports.setUp = function(callback) {
callback();
}

/**
* Retrieve the server information for the current
* instance of the db client
*
* @ignore
*/
exports.tearDown = function(callback) {
callback();
}

/**
* @ignore
*/
exports['Pass all corrupt BSON scenarios ./compliance/corrupt.json'] = function(test) {
// Read and parse the json file
var scenarios = require(__dirname + '/compliance/corrupt');

// Create a new BSON instance
var bson = new BSON([BSON.Binary, BSON.Code, BSON.DBRef, BSON.Decimal128,
BSON.Double, BSON.Int32, BSON.Long, BSON.Map, BSON.MaxKey, BSON.MinKey,
BSON.ObjectId, BSON.BSONRegExp, BSON.Symbol, BSON.Timestamp]);

for(var i = 0; i < scenarios.documents.length; i++) {
var doc = scenarios.documents[i];
if(doc.skip) continue;

try {
// Create a buffer containing the payload
var buffer = new Buffer(doc.encoded, 'hex');
// Attempt to deserialize
var object = bson.deserialize(buffer);
test.ok(false);
} catch(err) {
}
}

test.done();
}

/**
* @ignore
*/
exports['Pass all valid BSON serialization scenarios ./compliance/valid.json'] = function(test) {
// Read and parse the json file
var scenarios = require(__dirname + '/compliance/valid');

// Create a new BSON instance
var bson = new BSON();

// Translate extended json to correctly typed doc
var translate = function(doc, object) {
for(var name in doc) {
if(typeof doc[name] == 'number'
|| typeof doc[name] == 'string'
|| typeof doc[name] == 'boolean') {
object[name] = doc[name];
} else if(Array.isArray(doc[name])) {
object[name] = translate(doc[name], []);
} else if(doc[name]['$numberLong']) {
object[name] = Long.fromString(doc[name]['$numberLong']);
} else if(doc[name]['$undefined']) {
object[name] = null;
} else if(doc[name]['$date']) {
var date = new Date();
date.setTime(parseInt(doc[name]['$date']['$numberLong'], 10))
object[name] = date;
} else if(doc[name]['$regexp']) {
object[name] = new RegExp(doc[name]['$regexp'], doc[name]['$options'] || '');
} else if(doc[name]['$oid']) {
object[name] = new ObjectID(doc[name]['$oid']);
} else if(doc[name]['$binary']) {
object[name] = new Binary(doc[name]['$binary'], doc[name]['$type'] || 1);
} else if(doc[name]['$timestamp']) {
object[name] = Timestamp.fromBits(parseInt(doc[name]['$timestamp']['t'], 10), parseInt(doc[name]['$timestamp']['i']));
} else if(doc[name]['$ref']) {
object[name] = new DBRef(doc[name]['$ref'], doc[name]['$id']);
} else if(doc[name]['$minKey']) {
object[name] = new MinKey();
} else if(doc[name]['$maxKey']) {
object[name] = new MaxKey();
} else if(doc[name]['$code']) {
object[name] = new Code(doc[name]['$code'], doc[name]['$scope'] || {});
} else if(doc[name] != null && typeof doc[name] == 'object') {
object[name] = translate(doc[name], {});
}
}

return object;
}

// Iterate over all the results
scenarios.documents.forEach(function(doc) {
if(doc.skip) return;
// Create a buffer containing the payload
var expectedData = new Buffer(doc.encoded, 'hex');
// Get the expectedDocument
var expectedDocument = translate(doc.document, {});
// Serialize to buffer
var buffer = bson.serialize(expectedDocument);
// Validate the output
test.equal(expectedData.toString('hex'), buffer.toString('hex'));
// Attempt to deserialize
var object = bson.deserialize(buffer, {promoteLongs:false});
// // Validate the object
test.deepEqual(JSON.stringify(expectedDocument), JSON.stringify(object));
});

test.done();
}
Loading

0 comments on commit ef25d9d

Please sign in to comment.