summaryrefslogtreecommitdiff
path: root/scripting/v8_wrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scripting/v8_wrapper.cpp')
-rw-r--r--scripting/v8_wrapper.cpp109
1 files changed, 77 insertions, 32 deletions
diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp
index 29a70ba..c4e6b7d 100644
--- a/scripting/v8_wrapper.cpp
+++ b/scripting/v8_wrapper.cpp
@@ -67,16 +67,15 @@ namespace mongo {
Local<v8::Object> mongoToV8( const BSONObj& m , bool array, bool readOnly ){
+ Local<v8::Object> o;
+
// handle DBRef. needs to come first. isn't it? (metagoto)
static string ref = "$ref";
if ( ref == m.firstElement().fieldName() ) {
const BSONElement& id = m["$id"];
if (!id.eoo()) { // there's no check on $id exitence in sm implementation. risky ?
v8::Function* dbRef = getNamedCons( "DBRef" );
- v8::Handle<v8::Value> argv[2];
- argv[0] = mongoToV8Element(m.firstElement());
- argv[1] = mongoToV8Element(m["$id"]);
- return dbRef->NewInstance(2, argv);
+ o = dbRef->NewInstance();
}
}
@@ -85,9 +84,11 @@ namespace mongo {
Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
internalFieldObjects->SetInternalFieldCount( 1 );
- Local<v8::Object> o;
- if ( array ) {
- // NOTE Looks like it's impossible to add interceptors to non array objects in v8.
+ if ( !o.IsEmpty() ) {
+ readOnly = false;
+ } else if ( array ) {
+ // NOTE Looks like it's impossible to add interceptors to v8 arrays.
+ readOnly = false;
o = v8::Array::New();
} else if ( !readOnly ) {
o = v8::Object::New();
@@ -149,7 +150,6 @@ namespace mongo {
case mongo::NumberDouble:
case mongo::NumberInt:
- case mongo::NumberLong: // may lose information here - just copying sm engine behavior
o->Set( v8::String::New( f.fieldName() ) , v8::Number::New( f.number() ) );
break;
@@ -168,6 +168,7 @@ namespace mongo {
break;
case mongo::jstNULL:
+ case mongo::Undefined: // duplicate sm behavior
o->Set( v8::String::New( f.fieldName() ) , v8::Null() );
break;
@@ -200,7 +201,7 @@ namespace mongo {
case mongo::Timestamp: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
- sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) );
+ sub->Set( v8::String::New( "t" ) , v8::Number::New( f.timestampTime() ) );
sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) );
sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
@@ -208,6 +209,24 @@ namespace mongo {
break;
}
+ case mongo::NumberLong: {
+ Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
+ unsigned long long val = f.numberLong();
+ v8::Function* numberLong = getNamedCons( "NumberLong" );
+ if ( (long long)val == (long long)(double)(long long)(val) ) {
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = v8::Number::New( (double)(long long)( val ) );
+ o->Set( v8::String::New( f.fieldName() ), numberLong->NewInstance( 1, argv ) );
+ } else {
+ v8::Handle<v8::Value> argv[3];
+ argv[0] = v8::Number::New( (double)(long long)(val) );
+ argv[1] = v8::Integer::New( val >> 32 );
+ argv[2] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
+ o->Set( v8::String::New( f.fieldName() ), numberLong->NewInstance(3, argv) );
+ }
+ break;
+ }
+
case mongo::MinKey: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) );
@@ -224,10 +243,6 @@ namespace mongo {
break;
}
- case mongo::Undefined:
- o->Set( v8::String::New( f.fieldName() ), v8::Undefined() );
- break;
-
case mongo::DBRef: {
v8::Function* dbPointer = getNamedCons( "DBPointer" );
v8::Handle<v8::Value> argv[2];
@@ -247,7 +262,7 @@ namespace mongo {
}
- if ( !array && readOnly ) {
+ if ( readOnly ) {
readOnlyObjects->SetNamedPropertyHandler( 0, NamedReadOnlySet, 0, NamedReadOnlyDelete );
readOnlyObjects->SetIndexedPropertyHandler( 0, IndexedReadOnlySet, 0, IndexedReadOnlyDelete );
}
@@ -291,6 +306,7 @@ namespace mongo {
case mongo::EOO:
case mongo::jstNULL:
+ case mongo::Undefined: // duplicate sm behavior
return v8::Null();
case mongo::RegEx: {
@@ -319,12 +335,29 @@ namespace mongo {
case mongo::Timestamp: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
- sub->Set( v8::String::New( "time" ) , v8::Date::New( f.timestampTime() ) );
+ sub->Set( v8::String::New( "t" ) , v8::Number::New( f.timestampTime() ) );
sub->Set( v8::String::New( "i" ) , v8::Number::New( f.timestampInc() ) );
sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
return sub;
}
+
+ case mongo::NumberLong: {
+ Local<v8::Object> sub = internalFieldObjects->NewInstance();
+ unsigned long long val = f.numberLong();
+ v8::Function* numberLong = getNamedCons( "NumberLong" );
+ if ( (long long)val == (long long)(double)(long long)(val) ) {
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = v8::Number::New( (double)(long long)( val ) );
+ return numberLong->NewInstance( 1, argv );
+ } else {
+ v8::Handle<v8::Value> argv[3];
+ argv[0] = v8::Number::New( (double)(long long)( val ) );
+ argv[1] = v8::Integer::New( val >> 32 );
+ argv[2] = v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) );
+ return numberLong->NewInstance( 3, argv );
+ }
+ }
case mongo::MinKey: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
@@ -340,9 +373,6 @@ namespace mongo {
return sub;
}
- case mongo::Undefined:
- return v8::Undefined();
-
case mongo::DBRef: {
v8::Function* dbPointer = getNamedCons( "DBPointer" );
v8::Handle<v8::Value> argv[2];
@@ -362,7 +392,7 @@ namespace mongo {
return v8::Undefined();
}
- void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value ){
+ void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value , int depth ){
if ( value->IsString() ){
b.append( sname.c_str() , toSTLString( value ).c_str() );
@@ -383,7 +413,7 @@ namespace mongo {
}
if ( value->IsArray() ){
- BSONObj sub = v8ToMongo( value->ToObject() );
+ BSONObj sub = v8ToMongo( value->ToObject() , depth );
b.appendArray( sname.c_str() , sub );
return;
}
@@ -405,7 +435,7 @@ namespace mongo {
switch( obj->GetInternalField( 0 )->ToInt32()->Value() ) { // NOTE Uint32's Value() gave me a linking error, so going with this instead
case Timestamp:
b.appendTimestamp( sname.c_str(),
- Date_t( v8::Date::Cast( *obj->Get( v8::String::New( "time" ) ) )->NumberValue() ),
+ Date_t( obj->Get( v8::String::New( "t" ) )->ToNumber()->Value() ),
obj->Get( v8::String::New( "i" ) )->ToInt32()->Value() );
return;
case MinKey:
@@ -421,8 +451,8 @@ namespace mongo {
string s = toSTLString( value );
if ( s.size() && s[0] == '/' ){
s = s.substr( 1 );
- string r = s.substr( 0 , s.find( "/" ) );
- string o = s.substr( s.find( "/" ) + 1 );
+ string r = s.substr( 0 , s.rfind( "/" ) );
+ string o = s.substr( s.rfind( "/" ) + 1 );
b.appendRegex( sname.c_str() , r.c_str() , o.c_str() );
}
else if ( value->ToObject()->GetPrototype()->IsObject() &&
@@ -431,10 +461,23 @@ namespace mongo {
oid.init( toSTLString( value ) );
b.appendOID( sname.c_str() , &oid );
}
- else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) {
+ else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__NumberLong" ) ).IsEmpty() ) {
// TODO might be nice to potentially speed this up with an indexed internal
// field, but I don't yet know how to use an ObjectTemplate with a
// constructor.
+ v8::Handle< v8::Object > it = value->ToObject();
+ long long val;
+ if ( !it->Has( v8::String::New( "top" ) ) ) {
+ val = (long long)( it->Get( v8::String::New( "floatApprox" ) )->NumberValue() );
+ } else {
+ val = (long long)
+ ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
+ (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
+ }
+
+ b.append( sname.c_str(), val );
+ }
+ else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__DBPointer" ) ).IsEmpty() ) {
OID oid;
oid.init( toSTLString( value->ToObject()->Get( v8::String::New( "id" ) ) ) );
string ns = toSTLString( value->ToObject()->Get( v8::String::New( "ns" ) ) );
@@ -450,7 +493,7 @@ namespace mongo {
mongo::BinDataType( obj->Get( v8::String::New( "type" ) )->ToInt32()->Value() ),
dataArray );
} else {
- BSONObj sub = v8ToMongo( value->ToObject() );
+ BSONObj sub = v8ToMongo( value->ToObject() , depth );
b.append( sname.c_str() , sub );
}
return;
@@ -474,12 +517,14 @@ namespace mongo {
cout << "don't know how to convert to mongo field [" << name << "]\t" << value << endl;
}
- BSONObj v8ToMongo( v8::Handle<v8::Object> o ){
+ BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth ){
BSONObjBuilder b;
-
- v8::Handle<v8::String> idName = v8::String::New( "_id" );
- if ( o->HasRealNamedProperty( idName ) ){
- v8ToMongoElement( b , idName , "_id" , o->Get( idName ) );
+
+ if ( depth == 0 ){
+ v8::Handle<v8::String> idName = v8::String::New( "_id" );
+ if ( o->HasRealNamedProperty( idName ) ){
+ v8ToMongoElement( b , idName , "_id" , o->Get( idName ) );
+ }
}
Local<v8::Array> names = o->GetPropertyNames();
@@ -493,10 +538,10 @@ namespace mongo {
v8::Local<v8::Value> value = o->Get( name );
const string sname = toSTLString( name );
- if ( sname == "_id" )
+ if ( depth == 0 && sname == "_id" )
continue;
- v8ToMongoElement( b , name , sname , value );
+ v8ToMongoElement( b , name , sname , value , depth + 1 );
}
return b.obj();
}