-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathbson_wrapper.cc
153 lines (138 loc) · 5.65 KB
/
bson_wrapper.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "bson_wrapper.h"
int bson_append_from_v8_primitive(bson_t *b, v8::Isolate* isolate, v8::Local<v8::Value> src, const char* key, const int keyLen) {
if (src->IsNumber()) {
return bson_append_double(b, key, keyLen, Nan::To<double>(src).FromJust());
}
if (src->IsBoolean()) {
return bson_append_bool(b, key, keyLen, Nan::To<bool>(src).FromJust());
}
if (src->IsNull()) {
return bson_append_null(b, key, keyLen);
}
if (src->IsString()) {
v8::String::Utf8Value valueString(isolate, Nan::To<v8::String>(src).ToLocalChecked());
return bson_append_utf8(b, key, keyLen,
*valueString, valueString.length());
}
if (node::Buffer::HasInstance(src)) {
return bson_append_binary(b, key, keyLen, BSON_SUBTYPE_BINARY, (uint8_t*)node::Buffer::Data(src), node::Buffer::Length(src));
}
return -1;
}
v8::Local<v8::Value> v8_value_from_bson_value(const bson_value_t* v) {
switch(v->value_type) {
case BSON_TYPE_DOUBLE:
return Nan::New<v8::Number>(v->value.v_double);
case BSON_TYPE_NULL:
return Nan::Null();
case BSON_TYPE_BOOL:
return Nan::New<v8::Boolean>(v->value.v_bool);
case BSON_TYPE_UTF8:
return Nan::New<v8::String>(v->value.v_utf8.str, v->value.v_utf8.len).ToLocalChecked();
case BSON_TYPE_BINARY:
return Nan::CopyBuffer((const char*)v->value.v_binary.data, v->value.v_binary.data_len).ToLocalChecked();
default:
return Nan::Undefined();
}
}
bson_t* bson_new_from_v8_value(v8::Isolate* isolate, v8::Local<v8::Value> src, const char* key = NULL, int keyLen = 0, bson_t* parent = NULL) {
bson_t* b;
if (parent == NULL) {
b = bson_new();
if (!src->IsObject() || src->IsNull()) {
bson_append_from_v8_primitive(b, isolate, src, SHM_INTERNAL_KEY, SHM_INTERNAL_KEY_LEN);
return b;
}
parent = b;
}
bson_t child;
if (src->IsArray()) {
bson_append_array_begin(parent, key == NULL ? SHM_INTERNAL_KEY : key, key == NULL ? SHM_INTERNAL_KEY_LEN : keyLen, &child);
} else {
bson_append_document_begin(parent, key == NULL ? SHM_INTERNAL_KEY : key, key == NULL ? SHM_INTERNAL_KEY_LEN : keyLen, &child);
}
v8::Local<v8::Object> obj = Nan::To<v8::Object>(src).ToLocalChecked();
v8::Local<v8::Array> keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked();
uint32_t length = keys->Length();
for(uint32_t i = 0; i < length; i++) {
v8::Local<v8::Value> key = Nan::Get(keys, i).ToLocalChecked();
v8::String::Utf8Value keyString(isolate, Nan::To<v8::String>(key).ToLocalChecked());
v8::Local<v8::Value> value = Nan::Get(obj, key).ToLocalChecked();
if (!value->IsObject() || value->IsNull() || node::Buffer::HasInstance(value)) {
bson_append_from_v8_primitive(&child, isolate, value, *keyString, keyString.length());
} else if (value->IsObject()) {
bson_new_from_v8_value(isolate, value, *keyString, keyString.length(), &child);
}
}
if (src->IsArray()) {
bson_append_array_end(parent, &child);
} else {
bson_append_document_end(parent, &child);
}
return parent;
}
v8::Local<v8::Value> v8_value_from_bson_iter(bson_iter_t* iter, v8::Local<v8::Value> t) {
while(bson_iter_next(iter)) {
const char* key = bson_iter_key(iter);
const bson_value_t* value = bson_iter_value(iter);
bson_iter_t child;
v8::Local<v8::Value> target;
if (value->value_type == BSON_TYPE_ARRAY) {
target = Nan::New<v8::Array>();
} else if (value->value_type == BSON_TYPE_DOCUMENT) {
target = Nan::New<v8::Object>();
} else {
Nan::Set(Nan::To<v8::Object>(t).ToLocalChecked(),
Nan::New<v8::String>(key).ToLocalChecked(),
Nan::New<v8::Value>(v8_value_from_bson_value(value)));
continue;
}
Nan::Set(Nan::To<v8::Object>(t).ToLocalChecked(),
Nan::New<v8::String>(key).ToLocalChecked(),
target);
bson_iter_recurse(iter, &child);
v8_value_from_bson_iter(&child, target);
}
return t;
}
v8::Local<v8::Value> v8_value_from_bson(bson_t* b) {
bson_iter_t iter;
if ( bson_iter_init(&iter, b) && bson_iter_next(&iter)){
const char* key = bson_iter_key(&iter);
const bson_value_t* value = bson_iter_value(&iter);
v8::Local<v8::Value> target;
if (strncmp(key, SHM_INTERNAL_KEY, SHM_INTERNAL_KEY_LEN) == 0) {
if (value->value_type == BSON_TYPE_ARRAY) {
target = Nan::New<v8::Array>();
} else if (value->value_type == BSON_TYPE_DOCUMENT) {
target = Nan::New<v8::Object>();
} else {
return v8_value_from_bson_value(value);
}
bson_iter_t child;
bson_iter_recurse(&iter, &child);
return v8_value_from_bson_iter(&child, target);
}
}
// TODO
return Nan::Undefined();
}
BSONWrapper::BSONWrapper(v8::Local<v8::Value> src, v8::Isolate* isolate) {
b = bson_new_from_v8_value(isolate, src, NULL, 0, NULL);
}
BSONWrapper::BSONWrapper(const char* data, int length) {
const uint8_t* udata = reinterpret_cast<const uint8_t*>(data);
b = bson_new_from_data(udata, length);
}
const char* BSONWrapper::getBuffer() {
return reinterpret_cast<const char*>(bson_get_data(b));
}
int BSONWrapper::getBufferLen() {
return b->len;
}
v8::Local<v8::Value> BSONWrapper::getValue() {
return v8_value_from_bson(b);
}
BSONWrapper::~BSONWrapper() {
bson_destroy(b);
}