Skip to content

Commit ce6419e

Browse files
committed
Added MinKey and MaxKey support to C++ parser
1 parent e1c472d commit ce6419e

File tree

4 files changed

+162
-44
lines changed

4 files changed

+162
-44
lines changed

external-libs/bson/bson.cc

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "code.h"
2020
#include "dbref.h"
2121
#include "symbol.h"
22+
#include "minkey.h"
23+
#include "maxkey.h"
2224

2325
using namespace v8;
2426
using namespace node;
@@ -40,7 +42,8 @@ const uint32_t BSON_DATA_CODE_W_SCOPE = 15;
4042
const uint32_t BSON_DATA_INT = 16;
4143
const uint32_t BSON_DATA_TIMESTAMP = 17;
4244
const uint32_t BSON_DATA_LONG = 18;
43-
45+
const uint32_t BSON_DATA_MIN_KEY = 0xff;
46+
const uint32_t BSON_DATA_MAX_KEY = 0x7f;
4447

4548
const int32_t BSON_INT32_MAX = (int32_t)2147483647L;
4649
const int32_t BSON_INT32_MIN = (int32_t)(-1) * 2147483648L;
@@ -559,7 +562,31 @@ uint32_t BSON::serialize(char *serialized_object, uint32_t index, Handle<Value>
559562
*(serialized_object + index + str->Length()) = '\0';
560563
// Adjust the index
561564
index = index + str->Length() + 1;
562-
}
565+
}
566+
} else if(MinKey::HasInstance(value)) {
567+
// Save the string at the offset provided
568+
*(serialized_object + index) = BSON_DATA_MIN_KEY;
569+
// Adjust writing position for the first byte
570+
index = index + 1;
571+
// Convert name to char*
572+
ssize_t len = DecodeBytes(name, UTF8);
573+
ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
574+
// Add null termiation for the string
575+
*(serialized_object + index + len) = '\0';
576+
// Adjust the index
577+
index = index + len + 1;
578+
} else if(MaxKey::HasInstance(value)) {
579+
// Save the string at the offset provided
580+
*(serialized_object + index) = BSON_DATA_MAX_KEY;
581+
// Adjust writing position for the first byte
582+
index = index + 1;
583+
// Convert name to char*
584+
ssize_t len = DecodeBytes(name, UTF8);
585+
ssize_t written = DecodeWrite((serialized_object + index), len, name, UTF8);
586+
// Add null termiation for the string
587+
*(serialized_object + index + len) = '\0';
588+
// Adjust the index
589+
index = index + len + 1;
563590
} else if(value->IsNull() || value->IsUndefined()) {
564591
// Save the string at the offset provided
565592
*(serialized_object + index) = BSON_DATA_NULL;
@@ -787,6 +814,9 @@ uint32_t BSON::serialize(char *serialized_object, uint32_t index, Handle<Value>
787814
|| constructorString->Equals(String::New("Binary"))
788815
|| constructorString->Equals(String::New("exports.DBRef"))
789816
|| constructorString->Equals(String::New("exports.Code"))
817+
|| constructorString->Equals(String::New("exports.Double"))
818+
|| constructorString->Equals(String::New("exports.MinKey"))
819+
|| constructorString->Equals(String::New("exports.MaxKey"))
790820
|| constructorString->Equals(String::New("exports.Symbol")))) {
791821

792822
// Throw an error due to wrong class
@@ -906,6 +936,7 @@ uint32_t BSON::calculate_object_size(Handle<Value> value) {
906936
if(db_ref_obj->db != NULL) obj->Set(String::New("$db"), dbref->Get(String::New("db")));
907937
// Calculate size
908938
object_size += BSON::calculate_object_size(obj);
939+
} else if(MinKey::HasInstance(value) || MaxKey::HasInstance(value)) {
909940
} else if(Symbol::HasInstance(value)) {
910941
// Unpack the dbref
911942
Local<Object> dbref = value->ToObject();
@@ -998,6 +1029,9 @@ uint32_t BSON::calculate_object_size(Handle<Value> value) {
9981029
|| constructorString->Equals(String::New("Binary"))
9991030
|| constructorString->Equals(String::New("exports.DBRef"))
10001031
|| constructorString->Equals(String::New("exports.Code"))
1032+
|| constructorString->Equals(String::New("exports.Double"))
1033+
|| constructorString->Equals(String::New("exports.MinKey"))
1034+
|| constructorString->Equals(String::New("exports.MaxKey"))
10011035
|| constructorString->Equals(String::New("exports.Symbol")))) {
10021036

10031037
// Throw an error due to wrong class
@@ -1104,7 +1138,7 @@ Handle<Value> BSON::deserialize(char *data, bool is_array_item) {
11041138
// While we have data left let's decode
11051139
while(index < size) {
11061140
// Read the first to bytes to indicate the type of object we are decoding
1107-
uint16_t type = BSON::deserialize_int8(data, index);
1141+
uint8_t type = BSON::deserialize_int8(data, index);
11081142
// Handles the internal size of the object
11091143
uint32_t insert_index = 0;
11101144
// Adjust index to skip type byte
@@ -1246,6 +1280,50 @@ Handle<Value> BSON::deserialize(char *data, bool is_array_item) {
12461280
}
12471281
// Free up the memory
12481282
free(string_name);
1283+
} else if(type == BSON_DATA_MIN_KEY) {
1284+
// Read the null terminated index String
1285+
char *string_name = BSON::extract_string(data, index);
1286+
if(string_name == NULL) return VException("Invalid C String found.");
1287+
// Let's create a new string
1288+
index = index + strlen(string_name) + 1;
1289+
// Handle array value if applicable
1290+
uint32_t insert_index = 0;
1291+
if(is_array_item) {
1292+
insert_index = atoi(string_name);
1293+
}
1294+
1295+
// Create new MinKey
1296+
MinKey *minKey = MinKey::New();
1297+
// Add the element to the object
1298+
if(is_array_item) {
1299+
return_array->Set(Number::New(insert_index), minKey->handle_);
1300+
} else {
1301+
return_data->Set(String::New(string_name), minKey->handle_);
1302+
}
1303+
// Free up the memory
1304+
free(string_name);
1305+
} else if(type == BSON_DATA_MAX_KEY) {
1306+
// Read the null terminated index String
1307+
char *string_name = BSON::extract_string(data, index);
1308+
if(string_name == NULL) return VException("Invalid C String found.");
1309+
// Let's create a new string
1310+
index = index + strlen(string_name) + 1;
1311+
// Handle array value if applicable
1312+
uint32_t insert_index = 0;
1313+
if(is_array_item) {
1314+
insert_index = atoi(string_name);
1315+
}
1316+
1317+
// Create new MinKey
1318+
MaxKey *maxKey = MaxKey::New();
1319+
// Add the element to the object
1320+
if(is_array_item) {
1321+
return_array->Set(Number::New(insert_index), maxKey->handle_);
1322+
} else {
1323+
return_data->Set(String::New(string_name), maxKey->handle_);
1324+
}
1325+
// Free up the memory
1326+
free(string_name);
12491327
} else if(type == BSON_DATA_NULL) {
12501328
// Read the null terminated index String
12511329
char *string_name = BSON::extract_string(data, index);
@@ -1870,6 +1948,8 @@ extern "C" void init(Handle<Object> target) {
18701948
DBRef::Initialize(target);
18711949
Timestamp::Initialize(target);
18721950
Symbol::Initialize(target);
1951+
MinKey::Initialize(target);
1952+
MaxKey::Initialize(target);
18731953
}
18741954

18751955
// NODE_MODULE(bson, BSON::Initialize);

external-libs/bson/wscript

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def configure(conf):
2626
def build(bld):
2727
obj = bld.new_task_gen("cxx", "shlib", "node_addon")
2828
obj.target = "bson"
29-
obj.source = ["bson.cc", "long.cc", "objectid.cc", "binary.cc", "code.cc", "dbref.cc", "timestamp.cc", "local.cc", "symbol.cc"]
29+
obj.source = ["bson.cc", "long.cc", "objectid.cc", "binary.cc", "code.cc", "dbref.cc", "timestamp.cc", "local.cc", "symbol.cc", "minkey.cc", "maxkey.cc"]
3030
# obj.uselib = "NODE"
3131

3232
def shutdown():

lib/mongodb/bson/bson.js

Lines changed: 61 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ BSON.BSON_DATA_CODE_W_SCOPE = 15;
4848
BSON.BSON_DATA_INT = 16;
4949
BSON.BSON_DATA_TIMESTAMP = 17;
5050
BSON.BSON_DATA_LONG = 18;
51+
BSON.BSON_DATA_MIN_KEY = 0xff;
52+
BSON.BSON_DATA_MAX_KEY = 0x7f;
5153

5254
// BSON BINARY DATA SUBTYPES
5355
BSON.BSON_BINARY_SUBTYPE_DEFAULT = 0;
@@ -88,7 +90,7 @@ BSON.calculateObjectSize = function(object) {
8890
var name = keys[keysIndex++];
8991
var value = currentObject[name];
9092

91-
if(value == null) {
93+
if(value == null | value instanceof MinKey || value instanceof MaxKey) {
9294
totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (1);
9395
} else if(typeof value == 'string') {
9496
totalLength += (name != null ? (Buffer.byteLength(name) + 1) : 0) + (Buffer.byteLength(value, 'utf8') + 4 + 1 + 1);
@@ -300,9 +302,6 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
300302
// Ajust index
301303
index = index + 8;
302304
} else {
303-
debug(value.toString())
304-
debug(long.toNumber().toString())
305-
306305
buffer[index + 3] = (lowBits >> 24) & 0xff;
307306
buffer[index + 2] = (lowBits >> 16) & 0xff;
308307
buffer[index + 1] = (lowBits >> 8) & 0xff;
@@ -327,21 +326,6 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
327326
}
328327
} else if(typeof value == 'number' || toString.call(value) === '[object Number]' ||
329328
value instanceof Double) {
330-
331-
// } else if((typeof value == 'number' || toString.call(value) === '[object Number]') &&
332-
// value == parseInt(value, 10) &&
333-
// value >= BSON.JS_INT_MIN && value <= BSON.JS_INT_MAX) {
334-
//
335-
// debug("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
336-
// debug("====================== " + (typeof value == 'number'))
337-
// debug("====================== " + (toString.call(value) === '[object Number]'))
338-
// debug("====================== " + (value == parseInt(value, 10)))
339-
// debug("====================== " + (value >= parseInt(BSON.JS_INT_MIN, 10)))
340-
// debug("" + value + " = " + BSON.JS_INT_MIN)
341-
// debug("" + value + " = " + BSON.JS_INT_MAX)
342-
// debug(value.toString())
343-
// debug(value.toString().match(/\./))
344-
345329
// Write the type
346330
buffer[index++] = BSON.BSON_DATA_NUMBER;
347331
// Write the name
@@ -663,7 +647,23 @@ BSON.serializeWithBufferAndIndex = function serializeWithBufferAndIndex(object,
663647
// Update index
664648
index = index + size - 1;
665649
// Write zero
666-
buffer[index++] = 0;
650+
buffer[index++] = 0;
651+
} else if(value instanceof MinKey) {
652+
// Write the type of either Array or object
653+
buffer[index++] = BSON.BSON_DATA_MIN_KEY;
654+
// Write the name
655+
if(name != null) {
656+
index = index + buffer.write(name, index, 'utf8') + 1;
657+
buffer[index - 1] = 0;
658+
}
659+
} else if(value instanceof MaxKey) {
660+
// Write the type of either Array or object
661+
buffer[index++] = BSON.BSON_DATA_MAX_KEY;
662+
// Write the name
663+
if(name != null) {
664+
index = index + buffer.write(name, index, 'utf8') + 1;
665+
buffer[index - 1] = 0;
666+
}
667667
} else if(typeof value == 'object') {
668668
// Write the type of either Array or object
669669
buffer[index++] = Array.isArray(value) ? BSON.BSON_DATA_ARRAY : BSON.BSON_DATA_OBJECT;
@@ -1135,30 +1135,11 @@ BSON.deserialize = function(data, options) {
11351135
if (type === BSON.BSON_DATA_LONG) {
11361136
// Convert to long
11371137
value = new Long(low_bits, high_bits);
1138-
// Convert to number
1139-
11401138

1139+
// Convert to number
11411140
if(value.lessThanOrEqual(JS_INT_MAX_LONG) && value.greaterThanOrEqual(JS_INT_MIN_LONG)) {
1142-
// debug("--------------------------------------------------------------- 0")
11431141
value = value.toNumber();
11441142
}
1145-
1146-
1147-
// convert back to number and compare the converted value with the original
1148-
// var value2 = value.toNumber();
1149-
//
1150-
// // if(value2 > )
1151-
//
1152-
// // If Long string representiation is the same return the normal value
1153-
// debug("========================== :: " + Long.MAX_VALUE)
1154-
// debug("========================== :: " + BSON.JS_INT_MAX)
1155-
// debug("========================== :: " + Math.pow(2, 53))
1156-
// debug("========================== :: " + value.toString())
1157-
// debug("========================== :: " + value2.toString())
1158-
1159-
// if(value.toString() === value2.toString()) {
1160-
// value = value2;
1161-
// }
11621143
} else {
11631144
value = new Timestamp(low_bits, high_bits);
11641145
}
@@ -1217,6 +1198,32 @@ BSON.deserialize = function(data, options) {
12171198

12181199
// Set object property
12191200
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = value;
1201+
} else if(type === BSON.BSON_DATA_MIN_KEY) {
1202+
// Read the null terminated string (indexof until first 0)
1203+
string_end_index = index;
1204+
while(data[string_end_index++] !== 0);
1205+
string_end_index = string_end_index - 1;
1206+
1207+
// Fetch the string name
1208+
string_name = data.toString('utf8', index, string_end_index);
1209+
// Ajust index to point to the end of the string
1210+
index = string_end_index + 1;
1211+
1212+
// Set object property
1213+
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = new MinKey();
1214+
} else if(type === BSON.BSON_DATA_MAX_KEY) {
1215+
// Read the null terminated string (indexof until first 0)
1216+
string_end_index = index;
1217+
while(data[string_end_index++] !== 0);
1218+
string_end_index = string_end_index - 1;
1219+
1220+
// Fetch the string name
1221+
string_name = data.toString('utf8', index, string_end_index);
1222+
// Ajust index to point to the end of the string
1223+
index = string_end_index + 1;
1224+
1225+
// Set object property
1226+
currentObject[Array.isArray(currentObject) ? parseInt(string_name, 10) : string_name] = new MaxKey();
12201227
} else if(type === BSON.BSON_DATA_SYMBOL) {
12211228
// Read the null terminated string (indexof until first 0)
12221229
string_end_index = index;
@@ -1291,6 +1298,18 @@ Symbol.prototype.inspect = function() {
12911298
return this.value;
12921299
}
12931300

1301+
/**
1302+
* MinKey constructor
1303+
*
1304+
*/
1305+
function MinKey() {}
1306+
1307+
/**
1308+
* MaxKey constructor
1309+
*
1310+
*/
1311+
function MaxKey() {}
1312+
12941313
/**
12951314
* DBRef constructor.
12961315
*
@@ -1326,3 +1345,5 @@ exports.ObjectID = ObjectID;
13261345
exports.Long = Long;
13271346
exports.Timestamp = Timestamp;
13281347
exports.Double = Double;
1348+
exports.MinKey = MinKey;
1349+
exports.MaxKey = MaxKey;

test/bson/bson_test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ var testCase = require('../../deps/nodeunit').testCase,
1616
Symbol = mongodb.Symbol,
1717
DBRef = mongodb.DBRef,
1818
Double = mongodb.Double,
19+
MinKey = mongodb.MinKey,
20+
MaxKey = mongodb.MaxKey,
1921
BinaryParser = mongodb.BinaryParser;
2022

2123
// var m = require('../../lib/mongodb').pure();
@@ -1004,6 +1006,21 @@ var tests = testCase({
10041006
test.done();
10051007
},
10061008

1009+
'Should correctly serialize and deserialize MinKey and MaxKey values' : function(test) {
1010+
var doc = {
1011+
_id : new ObjectID("4e886e687ff7ef5e00000162"),
1012+
minKey : new MinKey(),
1013+
maxKey : new MaxKey()
1014+
}
1015+
1016+
var serialized_data = BSONSE.BSON.serialize(doc, false, true);
1017+
var doc2 = BSONSE.BSON.deserialize(serialized_data);
1018+
test.deepEqual(doc, doc2)
1019+
test.ok(doc2.minKey instanceof MinKey);
1020+
test.ok(doc2.maxKey instanceof MaxKey);
1021+
test.done();
1022+
},
1023+
10071024
// 'Should Correctly Function' : function(test) {
10081025
// var doc = {b:1, func:function() {
10091026
// this.b = 2;

0 commit comments

Comments
 (0)