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.cpp282
1 files changed, 145 insertions, 137 deletions
diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp
index 0e71c9a..ff67e8c 100644
--- a/scripting/v8_wrapper.cpp
+++ b/scripting/v8_wrapper.cpp
@@ -17,6 +17,7 @@
#include "v8_wrapper.h"
#include "v8_utils.h"
+#include "v8_db.h"
#include <iostream>
@@ -38,17 +39,17 @@ namespace mongo {
cout << "cannot delete from read-only object" << endl;
return Boolean::New( false );
}
-
+
Handle<Value> IndexedReadOnlySet( uint32_t index, Local<Value> value, const AccessorInfo& info ) {
cout << "cannot write to read-only array" << endl;
return value;
}
-
+
Handle<Boolean> IndexedReadOnlyDelete( uint32_t index, const AccessorInfo& info ) {
cout << "cannot delete from read-only array" << endl;
return Boolean::New( false );
}
-
+
Local< v8::Value > newFunction( const char *code ) {
stringstream codeSS;
codeSS << "____MontoToV8_newFunction_temp = " << code;
@@ -57,15 +58,15 @@ namespace mongo {
Local< Value > ret = compiled->Run();
return ret;
}
-
+
Local< v8::Value > newId( const OID &id ) {
v8::Function * idCons = getObjectIdCons();
v8::Handle<v8::Value> argv[1];
argv[0] = v8::String::New( id.str().c_str() );
- return idCons->NewInstance( 1 , argv );
+ return idCons->NewInstance( 1 , argv );
}
-
- Local<v8::Object> mongoToV8( const BSONObj& m , bool array, bool readOnly ){
+
+ Local<v8::Object> mongoToV8( const BSONObj& m , bool array, bool readOnly ) {
Local<v8::Object> o;
@@ -86,13 +87,16 @@ namespace mongo {
if ( !o.IsEmpty() ) {
readOnly = false;
- } else if ( array ) {
+ }
+ else if ( array ) {
// NOTE Looks like it's impossible to add interceptors to v8 arrays.
readOnly = false;
o = v8::Array::New();
- } else if ( !readOnly ) {
+ }
+ else if ( !readOnly ) {
o = v8::Object::New();
- } else {
+ }
+ else {
// NOTE Our readOnly implemention relies on undocumented ObjectTemplate
// functionality that may be fragile, but it still seems like the best option
// for now -- fwiw, the v8 docs are pretty sparse. I've determined experimentally
@@ -115,15 +119,15 @@ namespace mongo {
readOnlyObjects->SetIndexedPropertyHandler( 0 );
o = readOnlyObjects->NewInstance();
}
-
+
mongo::BSONObj sub;
for ( BSONObjIterator i(m); i.more(); ) {
const BSONElement& f = i.next();
-
+
Local<Value> v;
-
- switch ( f.type() ){
+
+ switch ( f.type() ) {
case mongo::Code:
o->Set( v8::String::New( f.fieldName() ), newFunction( f.valuestr() ) );
@@ -134,31 +138,31 @@ namespace mongo {
log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
o->Set( v8::String::New( f.fieldName() ), newFunction( f.codeWScopeCode() ) );
break;
-
- case mongo::String:
+
+ case mongo::String:
o->Set( v8::String::New( f.fieldName() ) , v8::String::New( f.valuestr() ) );
break;
-
+
case mongo::jstOID: {
v8::Function * idCons = getObjectIdCons();
v8::Handle<v8::Value> argv[1];
argv[0] = v8::String::New( f.__oid().str().c_str() );
- o->Set( v8::String::New( f.fieldName() ) ,
- idCons->NewInstance( 1 , argv ) );
+ o->Set( v8::String::New( f.fieldName() ) ,
+ idCons->NewInstance( 1 , argv ) );
break;
}
-
+
case mongo::NumberDouble:
case mongo::NumberInt:
o->Set( v8::String::New( f.fieldName() ) , v8::Number::New( f.number() ) );
break;
-
+
case mongo::Array:
case mongo::Object:
sub = f.embeddedObject();
o->Set( v8::String::New( f.fieldName() ) , mongoToV8( sub , f.type() == mongo::Array, readOnly ) );
break;
-
+
case mongo::Date:
o->Set( v8::String::New( f.fieldName() ) , v8::Date::New( f.date() ) );
break;
@@ -166,29 +170,29 @@ namespace mongo {
case mongo::Bool:
o->Set( v8::String::New( f.fieldName() ) , v8::Boolean::New( f.boolean() ) );
break;
-
+
case mongo::jstNULL:
case mongo::Undefined: // duplicate sm behavior
o->Set( v8::String::New( f.fieldName() ) , v8::Null() );
break;
-
+
case mongo::RegEx: {
v8::Function * regex = getNamedCons( "RegExp" );
-
+
v8::Handle<v8::Value> argv[2];
argv[0] = v8::String::New( f.regex() );
argv[1] = v8::String::New( f.regexFlags() );
-
+
o->Set( v8::String::New( f.fieldName() ) , regex->NewInstance( 2 , argv ) );
break;
}
-
+
case mongo::BinData: {
Local<v8::Object> b = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
int len;
const char *data = f.binData( len );
-
+
v8::Function* binData = getNamedCons( "BinData" );
v8::Handle<v8::Value> argv[3];
argv[0] = v8::Number::New( len );
@@ -197,36 +201,37 @@ namespace mongo {
o->Set( v8::String::New( f.fieldName() ), binData->NewInstance(3, argv) );
break;
}
-
+
case mongo::Timestamp: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
-
+
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() ) );
-
+
o->Set( v8::String::New( f.fieldName() ) , sub );
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];
+ 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 {
+ }
+ 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;
+ break;
}
-
+
case mongo::MinKey: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) );
@@ -234,7 +239,7 @@ namespace mongo {
o->Set( v8::String::New( f.fieldName() ) , sub );
break;
}
-
+
case mongo::MaxKey: {
Local<v8::Object> sub = readOnly ? readOnlyObjects->NewInstance() : internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MaxKey" ), v8::Boolean::New( true ) );
@@ -251,7 +256,7 @@ namespace mongo {
o->Set( v8::String::New( f.fieldName() ), dbPointer->NewInstance(2, argv) );
break;
}
-
+
default:
cout << "can't handle type: ";
cout << f.type() << " ";
@@ -259,14 +264,14 @@ namespace mongo {
cout << endl;
break;
}
-
+
}
if ( readOnly ) {
readOnlyObjects->SetNamedPropertyHandler( 0, NamedReadOnlySet, 0, NamedReadOnlyDelete );
- readOnlyObjects->SetIndexedPropertyHandler( 0, IndexedReadOnlySet, 0, IndexedReadOnlyDelete );
+ readOnlyObjects->SetIndexedPropertyHandler( 0, IndexedReadOnlySet, 0, IndexedReadOnlyDelete );
}
-
+
return o;
}
@@ -274,56 +279,56 @@ namespace mongo {
Local< v8::ObjectTemplate > internalFieldObjects = v8::ObjectTemplate::New();
internalFieldObjects->SetInternalFieldCount( 1 );
- switch ( f.type() ){
+ switch ( f.type() ) {
case mongo::Code:
return newFunction( f.valuestr() );
-
+
case CodeWScope:
if ( f.codeWScopeObject().isEmpty() )
log() << "warning: CodeWScope doesn't transfer to db.eval" << endl;
return newFunction( f.codeWScopeCode() );
-
- case mongo::String:
+
+ case mongo::String:
return v8::String::New( f.valuestr() );
-
+
case mongo::jstOID:
return newId( f.__oid() );
-
+
case mongo::NumberDouble:
case mongo::NumberInt:
return v8::Number::New( f.number() );
-
+
case mongo::Array:
case mongo::Object:
return mongoToV8( f.embeddedObject() , f.type() == mongo::Array );
-
+
case mongo::Date:
return v8::Date::New( f.date() );
-
+
case mongo::Bool:
return v8::Boolean::New( f.boolean() );
- case mongo::EOO:
+ case mongo::EOO:
case mongo::jstNULL:
case mongo::Undefined: // duplicate sm behavior
return v8::Null();
-
+
case mongo::RegEx: {
v8::Function * regex = getNamedCons( "RegExp" );
-
+
v8::Handle<v8::Value> argv[2];
argv[0] = v8::String::New( f.regex() );
argv[1] = v8::String::New( f.regexFlags() );
-
+
return regex->NewInstance( 2 , argv );
break;
}
-
+
case mongo::BinData: {
int len;
const char *data = f.binData( len );
-
+
v8::Function* binData = getNamedCons( "BinData" );
v8::Handle<v8::Value> argv[3];
argv[0] = v8::Number::New( len );
@@ -331,26 +336,27 @@ namespace mongo {
argv[2] = v8::String::New( data, len );
return binData->NewInstance( 3, argv );
};
-
+
case mongo::Timestamp: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
-
+
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];
+ v8::Handle<v8::Value> argv[1];
argv[0] = v8::Number::New( (double)(long long)( val ) );
return numberLong->NewInstance( 1, argv );
- } else {
+ }
+ else {
v8::Handle<v8::Value> argv[3];
argv[0] = v8::Number::New( (double)(long long)( val ) );
argv[1] = v8::Integer::New( val >> 32 );
@@ -358,21 +364,21 @@ namespace mongo {
return numberLong->NewInstance( 3, argv );
}
}
-
+
case mongo::MinKey: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MinKey" ), v8::Boolean::New( true ) );
sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
return sub;
}
-
+
case mongo::MaxKey: {
Local<v8::Object> sub = internalFieldObjects->NewInstance();
sub->Set( v8::String::New( "$MaxKey" ), v8::Boolean::New( true ) );
sub->SetInternalField( 0, v8::Uint32::New( f.type() ) );
return sub;
}
-
+
case mongo::DBRef: {
v8::Function* dbPointer = getNamedCons( "DBPointer" );
v8::Handle<v8::Value> argv[2];
@@ -380,83 +386,83 @@ namespace mongo {
argv[1] = newId( f.dbrefOID() );
return dbPointer->NewInstance(2, argv);
}
-
+
default:
cout << "can't handle type: ";
- cout << f.type() << " ";
- cout << f.toString();
- cout << endl;
+ cout << f.type() << " ";
+ cout << f.toString();
+ cout << endl;
break;
- }
-
+ }
+
return v8::Undefined();
}
- void v8ToMongoElement( BSONObjBuilder & b , v8::Handle<v8::String> name , const string sname , v8::Handle<v8::Value> value , int depth ){
-
- if ( value->IsString() ){
+ 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 , toSTLString( value ).c_str() );
return;
}
-
- if ( value->IsFunction() ){
- b.appendCode( sname , toSTLString( value ).c_str() );
+
+ if ( value->IsFunction() ) {
+ b.appendCode( sname , toSTLString( value ) );
return;
}
-
- if ( value->IsNumber() ){
+
+ if ( value->IsNumber() ) {
if ( value->IsInt32() )
b.append( sname, int( value->ToInt32()->Value() ) );
else
b.append( sname , value->ToNumber()->Value() );
return;
}
-
- if ( value->IsArray() ){
+
+ if ( value->IsArray() ) {
BSONObj sub = v8ToMongo( value->ToObject() , depth );
b.appendArray( sname , sub );
return;
}
-
- if ( value->IsDate() ){
+
+ if ( value->IsDate() ) {
b.appendDate( sname , Date_t( (unsigned long long)(v8::Date::Cast( *value )->NumberValue())) );
return;
}
if ( value->IsExternal() )
return;
-
- if ( value->IsObject() ){
+
+ if ( value->IsObject() ) {
// The user could potentially modify the fields of these special objects,
// wreaking havoc when we attempt to reinterpret them. Not doing any validation
// for now...
Local< v8::Object > obj = value->ToObject();
if ( obj->InternalFieldCount() && obj->GetInternalField( 0 )->IsNumber() ) {
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,
- Date_t( (unsigned long long)(obj->Get( v8::String::New( "t" ) )->ToNumber()->Value() )),
- obj->Get( v8::String::New( "i" ) )->ToInt32()->Value() );
- return;
- case MinKey:
- b.appendMinKey( sname );
- return;
- case MaxKey:
- b.appendMaxKey( sname );
- return;
- default:
- assert( "invalid internal field" == 0 );
+ case Timestamp:
+ b.appendTimestamp( sname,
+ Date_t( (unsigned long long)(obj->Get( v8::String::New( "t" ) )->ToNumber()->Value() )),
+ obj->Get( v8::String::New( "i" ) )->ToInt32()->Value() );
+ return;
+ case MinKey:
+ b.appendMinKey( sname );
+ return;
+ case MaxKey:
+ b.appendMaxKey( sname );
+ return;
+ default:
+ assert( "invalid internal field" == 0 );
}
}
string s = toSTLString( value );
- if ( s.size() && s[0] == '/' ){
+ if ( s.size() && s[0] == '/' ) {
s = s.substr( 1 );
string r = s.substr( 0 , s.rfind( "/" ) );
string o = s.substr( s.rfind( "/" ) + 1 );
- b.appendRegex( sname , r.c_str() , o.c_str() );
+ b.appendRegex( sname , r , o );
}
else if ( value->ToObject()->GetPrototype()->IsObject() &&
- value->ToObject()->GetPrototype()->ToObject()->HasRealNamedProperty( v8::String::New( "isObjectId" ) ) ){
+ value->ToObject()->GetPrototype()->ToObject()->HasRealNamedProperty( v8::String::New( "isObjectId" ) ) ) {
OID oid;
oid.init( toSTLString( value ) );
b.appendOID( sname , &oid );
@@ -469,19 +475,20 @@ namespace mongo {
long long val;
if ( !it->Has( v8::String::New( "top" ) ) ) {
val = (long long)( it->Get( v8::String::New( "floatApprox" ) )->NumberValue() );
- } else {
+ }
+ 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() );
+ ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
+ (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
}
-
+
b.append( sname, 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" ) ) );
- b.appendDBRef( sname, ns.c_str(), oid );
+ b.appendDBRef( sname, ns, oid );
}
else if ( !value->ToObject()->GetHiddenValue( v8::String::New( "__BinData" ) ).IsEmpty() ) {
int len = obj->Get( v8::String::New( "len" ) )->ToInt32()->Value();
@@ -489,27 +496,28 @@ namespace mongo {
const char *dataArray = *data;
assert( data.length() == len );
b.appendBinData( sname,
- len,
- mongo::BinDataType( obj->Get( v8::String::New( "type" ) )->ToInt32()->Value() ),
- dataArray );
- } else {
+ len,
+ mongo::BinDataType( obj->Get( v8::String::New( "type" ) )->ToInt32()->Value() ),
+ dataArray );
+ }
+ else {
BSONObj sub = v8ToMongo( value->ToObject() , depth );
b.append( sname , sub );
}
return;
}
-
- if ( value->IsBoolean() ){
+
+ if ( value->IsBoolean() ) {
b.appendBool( sname , value->ToBoolean()->Value() );
return;
}
-
- else if ( value->IsUndefined() ){
+
+ else if ( value->IsUndefined() ) {
b.appendUndefined( sname );
return;
}
-
- else if ( value->IsNull() ){
+
+ else if ( value->IsNull() ) {
b.appendNull( sname );
return;
}
@@ -517,26 +525,26 @@ namespace mongo {
cout << "don't know how to convert to mongo field [" << name << "]\t" << value << endl;
}
- BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth ){
+ BSONObj v8ToMongo( v8::Handle<v8::Object> o , int depth ) {
BSONObjBuilder b;
-
- if ( depth == 0 ){
+
+ if ( depth == 0 ) {
v8::Handle<v8::String> idName = v8::String::New( "_id" );
- if ( o->HasRealNamedProperty( idName ) ){
+ if ( o->HasRealNamedProperty( idName ) ) {
v8ToMongoElement( b , idName , "_id" , o->Get( idName ) );
}
}
-
+
Local<v8::Array> names = o->GetPropertyNames();
- for ( unsigned int i=0; i<names->Length(); i++ ){
+ for ( unsigned int i=0; i<names->Length(); i++ ) {
v8::Local<v8::String> name = names->Get(v8::Integer::New(i) )->ToString();
if ( o->GetPrototype()->IsObject() &&
- o->GetPrototype()->ToObject()->HasRealNamedProperty( name ) )
+ o->GetPrototype()->ToObject()->HasRealNamedProperty( name ) )
continue;
-
+
v8::Local<v8::Value> value = o->Get( name );
-
+
const string sname = toSTLString( name );
if ( depth == 0 && sname == "_id" )
continue;
@@ -553,15 +561,15 @@ namespace mongo {
WrapperHolder( const BSONObj * o , bool readOnly , bool iDelete )
: _o(o), _readOnly( readOnly ), _iDelete( iDelete ) {
}
-
- ~WrapperHolder(){
- if ( _o && _iDelete ){
+
+ ~WrapperHolder() {
+ if ( _o && _iDelete ) {
delete _o;
}
_o = 0;
}
- v8::Handle<v8::Value> get( v8::Local<v8::String> name ){
+ v8::Handle<v8::Value> get( v8::Local<v8::String> name ) {
const string& s = toSTLString( name );
const BSONElement& e = _o->getField( s );
return mongoToV8Element(e);
@@ -572,13 +580,13 @@ namespace mongo {
bool _iDelete;
};
- WrapperHolder * createWrapperHolder( const BSONObj * o , bool readOnly , bool iDelete ){
+ WrapperHolder * createWrapperHolder( const BSONObj * o , bool readOnly , bool iDelete ) {
return new WrapperHolder( o , readOnly , iDelete );
}
#define WRAPPER_STRING (v8::String::New( "_wrapper" ) )
- WrapperHolder * getWrapper( v8::Handle<v8::Object> o ){
+ WrapperHolder * getWrapper( v8::Handle<v8::Object> o ) {
Handle<v8::Value> t = o->GetRealNamedProperty( WRAPPER_STRING );
assert( t->IsExternal() );
Local<External> c = External::Cast( *t );
@@ -588,32 +596,32 @@ namespace mongo {
}
- Handle<Value> wrapperCons(const Arguments& args){
+ Handle<Value> wrapperCons(const Arguments& args) {
if ( ! ( args.Length() == 1 && args[0]->IsExternal() ) )
return v8::ThrowException( v8::String::New( "wrapperCons needs 1 External arg" ) );
args.This()->Set( WRAPPER_STRING , args[0] );
-
+
return v8::Undefined();
}
- v8::Handle<v8::Value> wrapperGetHandler( v8::Local<v8::String> name, const v8::AccessorInfo &info){
+ v8::Handle<v8::Value> wrapperGetHandler( v8::Local<v8::String> name, const v8::AccessorInfo &info) {
return getWrapper( info.This() )->get( name );
}
- v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate(){
- v8::Local<v8::FunctionTemplate> t = FunctionTemplate::New( wrapperCons );
+ v8::Handle<v8::FunctionTemplate> getObjectWrapperTemplate() {
+ v8::Local<v8::FunctionTemplate> t = newV8Function< wrapperCons >();
t->InstanceTemplate()->SetNamedPropertyHandler( wrapperGetHandler );
return t;
}
// --- random utils ----
- v8::Function * getNamedCons( const char * name ){
+ v8::Function * getNamedCons( const char * name ) {
return v8::Function::Cast( *(v8::Context::GetCurrent()->Global()->Get( v8::String::New( name ) ) ) );
}
- v8::Function * getObjectIdCons(){
+ v8::Function * getObjectIdCons() {
return getNamedCons( "ObjectId" );
}