diff options
Diffstat (limited to 'scripting/v8_db.cpp')
-rw-r--r-- | scripting/v8_db.cpp | 605 |
1 files changed, 390 insertions, 215 deletions
diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp index 4d12454..bda549c 100644 --- a/scripting/v8_db.cpp +++ b/scripting/v8_db.cpp @@ -15,10 +15,18 @@ * limitations under the License. */ +#if defined(_WIN32) +/** this is a hack - v8stdint.h defined uint16_t etc. on _WIN32 only, and that collides with + our usage of boost */ +#include "boost/cstdint.hpp" +using namespace boost; +#define V8STDINT_H_ +#endif + #include "v8_wrapper.h" #include "v8_utils.h" -#include "v8_db.h" #include "engine_v8.h" +#include "v8_db.h" #include "util/base64.h" #include "util/text.h" #include "../client/syncclusterconnection.h" @@ -32,127 +40,161 @@ namespace mongo { #define DDD(x) - v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ) { - v8::Local<v8::FunctionTemplate> mongo; + v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( V8Scope* scope, bool local ) { + v8::Handle<v8::FunctionTemplate> mongo; if ( local ) { - mongo = newV8Function< mongoConsLocal >(); + mongo = scope->createV8Function(mongoConsLocal); } else { - mongo = newV8Function< mongoConsExternal >(); + mongo = scope->createV8Function(mongoConsExternal); } mongo->InstanceTemplate()->SetInternalFieldCount( 1 ); + v8::Handle<v8::Template> proto = mongo->PrototypeTemplate(); + scope->injectV8Function("find", mongoFind, proto); + scope->injectV8Function("insert", mongoInsert, proto); + scope->injectV8Function("remove", mongoRemove, proto); + scope->injectV8Function("update", mongoUpdate, proto); - v8::Local<v8::Template> proto = mongo->PrototypeTemplate(); - - proto->Set( v8::String::New( "find" ) , newV8Function< mongoFind >() ); - proto->Set( v8::String::New( "insert" ) , newV8Function< mongoInsert >() ); - proto->Set( v8::String::New( "remove" ) , newV8Function< mongoRemove >() ); - proto->Set( v8::String::New( "update" ) , newV8Function< mongoUpdate >() ); - - Local<FunctionTemplate> ic = newV8Function< internalCursorCons >(); + v8::Handle<FunctionTemplate> ic = scope->createV8Function(internalCursorCons); ic->InstanceTemplate()->SetInternalFieldCount( 1 ); - ic->PrototypeTemplate()->Set( v8::String::New("next") , newV8Function< internalCursorNext >() ); - ic->PrototypeTemplate()->Set( v8::String::New("hasNext") , newV8Function< internalCursorHasNext >() ); - ic->PrototypeTemplate()->Set( v8::String::New("objsLeftInBatch") , newV8Function< internalCursorObjsLeftInBatch >() ); - proto->Set( v8::String::New( "internalCursor" ) , ic ); - - + v8::Handle<v8::Template> icproto = ic->PrototypeTemplate(); + scope->injectV8Function("next", internalCursorNext, icproto); + scope->injectV8Function("hasNext", internalCursorHasNext, icproto); + scope->injectV8Function("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto); + proto->Set( scope->getV8Str( "internalCursor" ) , ic ); return mongo; } - v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate() { - v8::Local<v8::FunctionTemplate> numberLong = newV8Function< numberLongInit >(); + v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit); v8::Local<v8::Template> proto = numberLong->PrototypeTemplate(); - - proto->Set( v8::String::New( "valueOf" ) , newV8Function< numberLongValueOf >() ); - proto->Set( v8::String::New( "toNumber" ) , newV8Function< numberLongToNumber >() ); - proto->Set( v8::String::New( "toString" ) , newV8Function< numberLongToString >() ); + scope->injectV8Function("valueOf", numberLongValueOf, proto); + scope->injectV8Function("toNumber", numberLongToNumber, proto); + scope->injectV8Function("toString", numberLongToString, proto); return numberLong; } - v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate() { - v8::Local<v8::FunctionTemplate> binData = newV8Function< binDataInit >(); - v8::Local<v8::Template> proto = binData->PrototypeTemplate(); + v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit); + v8::Local<v8::Template> proto = numberInt->PrototypeTemplate(); + scope->injectV8Function("valueOf", numberIntValueOf, proto); + scope->injectV8Function("toNumber", numberIntToNumber, proto); + scope->injectV8Function("toString", numberIntToString, proto); - proto->Set( v8::String::New( "toString" ) , newV8Function< binDataToString >() ); + return numberInt; + } + v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit); + binData->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::Template> proto = binData->PrototypeTemplate(); + scope->injectV8Function("toString", binDataToString, proto); + scope->injectV8Function("base64", binDataToBase64, proto); + scope->injectV8Function("hex", binDataToHex, proto); return binData; } - v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate() { - v8::Local<v8::FunctionTemplate> ts = newV8Function< dbTimestampInit >(); - v8::Local<v8::Template> proto = ts->PrototypeTemplate(); - - ts->InstanceTemplate()->SetInternalFieldCount( 1 ); - - return ts; + v8::Handle<v8::FunctionTemplate> getUUIDFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(uuidInit); + templ->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::Template> proto = templ->PrototypeTemplate(); + scope->injectV8Function("toString", binDataToString, proto); + scope->injectV8Function("base64", binDataToBase64, proto); + scope->injectV8Function("hex", binDataToHex, proto); + return templ; } + v8::Handle<v8::FunctionTemplate> getMD5FunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(md5Init); + templ->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::Template> proto = templ->PrototypeTemplate(); + scope->injectV8Function("toString", binDataToString, proto); + scope->injectV8Function("base64", binDataToBase64, proto); + scope->injectV8Function("hex", binDataToHex, proto); + return templ; + } - void installDBTypes( Handle<ObjectTemplate>& global ) { - v8::Local<v8::FunctionTemplate> db = newV8Function< dbInit >(); - db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - global->Set(v8::String::New("DB") , db ); - - v8::Local<v8::FunctionTemplate> dbCollection = newV8Function< collectionInit >(); - dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - global->Set(v8::String::New("DBCollection") , dbCollection ); - - - v8::Local<v8::FunctionTemplate> dbQuery = newV8Function< dbQueryInit >(); - dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess ); - global->Set(v8::String::New("DBQuery") , dbQuery ); - - global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >() ); - - global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >() ); - - global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >() ); - - global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate() ); + v8::Handle<v8::FunctionTemplate> getHexDataFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(hexDataInit); + templ->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::Template> proto = templ->PrototypeTemplate(); + scope->injectV8Function("toString", binDataToString, proto); + scope->injectV8Function("base64", binDataToBase64, proto); + scope->injectV8Function("hex", binDataToHex, proto); + return templ; + } - global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate() ); + v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) { + v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit); + v8::Local<v8::Template> proto = ts->PrototypeTemplate(); + ts->InstanceTemplate()->SetInternalFieldCount( 1 ); - global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate() ); + return ts; } - void installDBTypes( Handle<v8::Object>& global ) { - v8::Local<v8::FunctionTemplate> db = newV8Function< dbInit >(); +// void installDBTypes( V8Scope* scope, Handle<ObjectTemplate>& global ) { +// v8::Handle<v8::FunctionTemplate> db = scope->createV8Function(dbInit); +// db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); +// global->Set(v8::String::New("DB") , db ); +// +// v8::Handle<v8::FunctionTemplate> dbCollection = scope->createV8Function(collectionInit); +// dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); +// global->Set(v8::String::New("DBCollection") , dbCollection ); +// +// +// v8::Handle<v8::FunctionTemplate> dbQuery = scope->createV8Function(dbQueryInit); +// dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess ); +// global->Set(v8::String::New("DBQuery") , dbQuery ); +// +// global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >(scope) ); +// +// global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >(scope) ); +// +// global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >(scope) ); +// +// global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate(scope) ); +// +// global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate(scope) ); +// +// global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate(scope) ); +// } + + void installDBTypes( V8Scope* scope, v8::Handle<v8::Object>& global ) { + v8::Handle<v8::FunctionTemplate> db = scope->createV8Function(dbInit); db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - global->Set(v8::String::New("DB") , db->GetFunction() ); - - v8::Local<v8::FunctionTemplate> dbCollection = newV8Function< collectionInit >(); + global->Set(scope->getV8Str("DB") , db->GetFunction() ); + v8::Handle<v8::FunctionTemplate> dbCollection = scope->createV8Function(collectionInit); dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - global->Set(v8::String::New("DBCollection") , dbCollection->GetFunction() ); + global->Set(scope->getV8Str("DBCollection") , dbCollection->GetFunction() ); - v8::Local<v8::FunctionTemplate> dbQuery = newV8Function< dbQueryInit >(); + v8::Handle<v8::FunctionTemplate> dbQuery = scope->createV8Function(dbQueryInit); dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess ); - global->Set(v8::String::New("DBQuery") , dbQuery->GetFunction() ); - - global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >()->GetFunction() ); - - global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >()->GetFunction() ); + global->Set(scope->getV8Str("DBQuery") , dbQuery->GetFunction() ); - global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >()->GetFunction() ); + scope->injectV8Function("ObjectId", objectIdInit, global); + scope->injectV8Function("DBRef", dbRefInit, global); + scope->injectV8Function("DBPointer", dbPointerInit, global); - global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate()->GetFunction() ); - - global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate()->GetFunction() ); - - global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate()->GetFunction() ); + global->Set( scope->getV8Str("BinData") , getBinDataFunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("UUID") , getUUIDFunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("MD5") , getMD5FunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("HexData") , getHexDataFunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("NumberLong") , getNumberLongFunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("NumberInt") , getNumberIntFunctionTemplate(scope)->GetFunction() ); + global->Set( scope->getV8Str("Timestamp") , getTimestampFunctionTemplate(scope)->GetFunction() ); BSONObjBuilder b; b.appendMaxKey( "" ); b.appendMinKey( "" ); BSONObj o = b.obj(); BSONObjIterator i( o ); - global->Set( v8::String::New("MaxKey"), mongoToV8Element( i.next() ) ); - global->Set( v8::String::New("MinKey"), mongoToV8Element( i.next() ) ); + global->Set( scope->getV8Str("MaxKey"), scope->mongoToV8Element( i.next() ) ); + global->Set( scope->getV8Str("MinKey"), scope->mongoToV8Element( i.next() ) ); - global->Get( v8::String::New( "Object" ) )->ToObject()->Set( v8::String::New("bsonsize") , newV8Function< bsonsize >()->GetFunction() ); + global->Get( scope->getV8Str( "Object" ) )->ToObject()->Set( scope->getV8Str("bsonsize") , scope->createV8Function(bsonsize)->GetFunction() ); } void destroyConnection( Persistent<Value> self, void* parameter) { @@ -161,7 +203,7 @@ namespace mongo { self.Clear(); } - Handle<Value> mongoConsExternal(const Arguments& args) { + Handle<Value> mongoConsExternal(V8Scope* scope, const Arguments& args) { char host[255]; @@ -196,13 +238,13 @@ namespace mongo { } args.This()->SetInternalField( 0 , External::New( conn ) ); - args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); - args.This()->Set( v8::String::New( "host" ) , v8::String::New( host ) ); + args.This()->Set( scope->getV8Str( "slaveOk" ) , Boolean::New( false ) ); + args.This()->Set( scope->getV8Str( "host" ) , scope->getV8Str( host ) ); return v8::Undefined(); } - Handle<Value> mongoConsLocal(const Arguments& args) { + Handle<Value> mongoConsLocal(V8Scope* scope, const Arguments& args) { if ( args.Length() > 0 ) return v8::ThrowException( v8::String::New( "local Mongo constructor takes no args" ) ); @@ -218,8 +260,8 @@ namespace mongo { // NOTE I don't believe the conn object will ever be freed. args.This()->SetInternalField( 0 , External::New( conn ) ); - args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); - args.This()->Set( v8::String::New( "host" ) , v8::String::New( "EMBEDDED" ) ); + args.This()->Set( scope->getV8Str( "slaveOk" ) , Boolean::New( false ) ); + args.This()->Set( scope->getV8Str( "host" ) , scope->getV8Str( "EMBEDDED" ) ); return v8::Undefined(); } @@ -255,7 +297,7 @@ namespace mongo { 3 - limit 4 - skip */ - Handle<Value> mongoFind(const Arguments& args) { + Handle<Value> mongoFind(V8Scope* scope, const Arguments& args) { HandleScope handle_scope; jsassert( args.Length() == 7 , "find needs 7 args" ); @@ -263,16 +305,16 @@ namespace mongo { DBClientBase * conn = getConnection( args ); GETNS; - BSONObj q = v8ToMongo( args[1]->ToObject() ); + BSONObj q = scope->v8ToMongo( args[1]->ToObject() ); DDD( "query:" << q ); BSONObj fields; bool haveFields = args[2]->IsObject() && args[2]->ToObject()->GetPropertyNames()->Length() > 0; if ( haveFields ) - fields = v8ToMongo( args[2]->ToObject() ); + fields = scope->v8ToMongo( args[2]->ToObject() ); Local<v8::Object> mongo = args.This(); - Local<v8::Value> slaveOkVal = mongo->Get( v8::String::New( "slaveOk" ) ); + Local<v8::Value> slaveOkVal = mongo->Get( scope->getV8Str( "slaveOk" ) ); jsassert( slaveOkVal->IsBoolean(), "slaveOk member invalid" ); bool slaveOk = slaveOkVal->BooleanValue(); @@ -285,8 +327,10 @@ namespace mongo { { V8Unlock u; cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, options | ( slaveOk ? QueryOption_SlaveOk : 0 ) , batchSize ); + if ( ! cursor.get() ) + return v8::ThrowException( v8::String::New( "error doing query: failed" ) ); } - v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) ); + v8::Function * cons = (v8::Function*)( *( mongo->Get( scope->getV8Str( "internalCursor" ) ) ) ); assert( cons ); Persistent<v8::Object> c = Persistent<v8::Object>::New( cons->NewInstance() ); @@ -300,11 +344,11 @@ namespace mongo { } } - v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args) { + v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args) { jsassert( args.Length() == 2 , "insert needs 2 args" ); jsassert( args[1]->IsObject() , "have to insert an object" ); - if ( args.This()->Get( v8::String::New( "readOnly" ) )->BooleanValue() ) + if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() ) return v8::ThrowException( v8::String::New( "js db in read only mode" ) ); DBClientBase * conn = getConnection( args ); @@ -312,12 +356,12 @@ namespace mongo { v8::Handle<v8::Object> in = args[1]->ToObject(); - if ( ! in->Has( v8::String::New( "_id" ) ) ) { + if ( ! in->Has( scope->getV8Str( "_id" ) ) ) { v8::Handle<v8::Value> argv[1]; - in->Set( v8::String::New( "_id" ) , getObjectIdCons()->NewInstance( 0 , argv ) ); + in->Set( scope->getV8Str( "_id" ) , scope->getObjectIdCons()->NewInstance( 0 , argv ) ); } - BSONObj o = v8ToMongo( in ); + BSONObj o = scope->v8ToMongo( in ); DDD( "want to save : " << o.jsonString() ); try { @@ -331,18 +375,18 @@ namespace mongo { return v8::Undefined(); } - v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args) { + v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args) { jsassert( args.Length() == 2 || args.Length() == 3 , "remove needs 2 args" ); jsassert( args[1]->IsObject() , "have to remove an object template" ); - if ( args.This()->Get( v8::String::New( "readOnly" ) )->BooleanValue() ) + if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() ) return v8::ThrowException( v8::String::New( "js db in read only mode" ) ); DBClientBase * conn = getConnection( args ); GETNS; v8::Handle<v8::Object> in = args[1]->ToObject(); - BSONObj o = v8ToMongo( in ); + BSONObj o = scope->v8ToMongo( in ); bool justOne = false; if ( args.Length() > 2 ) { @@ -361,12 +405,12 @@ namespace mongo { return v8::Undefined(); } - v8::Handle<v8::Value> mongoUpdate(const v8::Arguments& args) { + v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args) { jsassert( args.Length() >= 3 , "update needs at least 3 args" ); jsassert( args[1]->IsObject() , "1st param to update has to be an object" ); jsassert( args[2]->IsObject() , "2nd param to update has to be an object" ); - if ( args.This()->Get( v8::String::New( "readOnly" ) )->BooleanValue() ) + if ( args.This()->Get( scope->getV8Str( "readOnly" ) )->BooleanValue() ) return v8::ThrowException( v8::String::New( "js db in read only mode" ) ); DBClientBase * conn = getConnection( args ); @@ -379,8 +423,8 @@ namespace mongo { bool multi = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value(); try { - BSONObj q1 = v8ToMongo( q ); - BSONObj o1 = v8ToMongo( o ); + BSONObj q1 = scope->v8ToMongo( q ); + BSONObj o1 = scope->v8ToMongo( o ); V8Unlock u; conn->update( ns , q1 , o1 , upsert, multi ); } @@ -403,11 +447,11 @@ namespace mongo { return cursor; } - v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args) { + v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args) { return v8::Undefined(); } - v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args) { + v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args) { mongo::DBClientCursor * cursor = getCursor( args ); if ( ! cursor ) return v8::Undefined(); @@ -416,10 +460,13 @@ namespace mongo { V8Unlock u; o = cursor->next(); } - return mongoToV8( o ); + bool ro = false; + if (args.This()->Has(scope->V8STR_RO)) + ro = args.This()->Get(scope->V8STR_RO)->BooleanValue(); + return scope->mongoToLZV8( o, false, ro ); } - v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args) { + v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) { mongo::DBClientCursor * cursor = getCursor( args ); if ( ! cursor ) return Boolean::New( false ); @@ -431,7 +478,7 @@ namespace mongo { return Boolean::New( ret ); } - v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args) { + v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, const v8::Arguments& args) { mongo::DBClientCursor * cursor = getCursor( args ); if ( ! cursor ) return v8::Number::New( (double) 0 ); @@ -443,14 +490,19 @@ namespace mongo { return v8::Number::New( (double) ret ); } +// v8::Handle<v8::Value> internalCursorReadOnly(V8Scope* scope, const v8::Arguments& args) { +// Local<v8::Object> cursor = args.This(); +// cursor->Set(scope->V8STR_RO, v8::Undefined()); +// return cursor; +// } // --- DB ---- - v8::Handle<v8::Value> dbInit(const v8::Arguments& args) { + v8::Handle<v8::Value> dbInit(V8Scope* scope, const v8::Arguments& args) { assert( args.Length() == 2 ); - args.This()->Set( v8::String::New( "_mongo" ) , args[0] ); - args.This()->Set( v8::String::New( "_name" ) , args[1] ); + args.This()->Set( scope->getV8Str( "_mongo" ) , args[0] ); + args.This()->Set( scope->getV8Str( "_name" ) , args[1] ); for ( int i=0; i<args.Length(); i++ ) assert( ! args[i]->IsUndefined() ); @@ -458,13 +510,13 @@ namespace mongo { return v8::Undefined(); } - v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> collectionInit( V8Scope* scope, const v8::Arguments& args ) { assert( args.Length() == 4 ); - args.This()->Set( v8::String::New( "_mongo" ) , args[0] ); - args.This()->Set( v8::String::New( "_db" ) , args[1] ); - args.This()->Set( v8::String::New( "_shortName" ) , args[2] ); - args.This()->Set( v8::String::New( "_fullName" ) , args[3] ); + args.This()->Set( scope->getV8Str( "_mongo" ) , args[0] ); + args.This()->Set( scope->getV8Str( "_db" ) , args[1] ); + args.This()->Set( scope->getV8Str( "_shortName" ) , args[2] ); + args.This()->Set( scope->getV8Str( "_fullName" ) , args[3] ); if ( haveLocalShardingInfo( toSTLString( args[3] ) ) ) return v8::ThrowException( v8::String::New( "can't use sharded collection from db.eval" ) ); @@ -475,52 +527,52 @@ namespace mongo { return v8::Undefined(); } - v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> dbQueryInit( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> t = args.This(); assert( args.Length() >= 4 ); - t->Set( v8::String::New( "_mongo" ) , args[0] ); - t->Set( v8::String::New( "_db" ) , args[1] ); - t->Set( v8::String::New( "_collection" ) , args[2] ); - t->Set( v8::String::New( "_ns" ) , args[3] ); + t->Set( scope->getV8Str( "_mongo" ) , args[0] ); + t->Set( scope->getV8Str( "_db" ) , args[1] ); + t->Set( scope->getV8Str( "_collection" ) , args[2] ); + t->Set( scope->getV8Str( "_ns" ) , args[3] ); if ( args.Length() > 4 && args[4]->IsObject() ) - t->Set( v8::String::New( "_query" ) , args[4] ); + t->Set( scope->getV8Str( "_query" ) , args[4] ); else - t->Set( v8::String::New( "_query" ) , v8::Object::New() ); + t->Set( scope->getV8Str( "_query" ) , v8::Object::New() ); if ( args.Length() > 5 && args[5]->IsObject() ) - t->Set( v8::String::New( "_fields" ) , args[5] ); + t->Set( scope->getV8Str( "_fields" ) , args[5] ); else - t->Set( v8::String::New( "_fields" ) , v8::Null() ); + t->Set( scope->getV8Str( "_fields" ) , v8::Null() ); if ( args.Length() > 6 && args[6]->IsNumber() ) - t->Set( v8::String::New( "_limit" ) , args[6] ); + t->Set( scope->getV8Str( "_limit" ) , args[6] ); else - t->Set( v8::String::New( "_limit" ) , Number::New( 0 ) ); + t->Set( scope->getV8Str( "_limit" ) , Number::New( 0 ) ); if ( args.Length() > 7 && args[7]->IsNumber() ) - t->Set( v8::String::New( "_skip" ) , args[7] ); + t->Set( scope->getV8Str( "_skip" ) , args[7] ); else - t->Set( v8::String::New( "_skip" ) , Number::New( 0 ) ); + t->Set( scope->getV8Str( "_skip" ) , Number::New( 0 ) ); if ( args.Length() > 8 && args[8]->IsNumber() ) - t->Set( v8::String::New( "_batchSize" ) , args[8] ); + t->Set( scope->getV8Str( "_batchSize" ) , args[8] ); else - t->Set( v8::String::New( "_batchSize" ) , Number::New( 0 ) ); + t->Set( scope->getV8Str( "_batchSize" ) , Number::New( 0 ) ); if ( args.Length() > 9 && args[9]->IsNumber() ) - t->Set( v8::String::New( "_options" ) , args[9] ); + t->Set( scope->getV8Str( "_options" ) , args[9] ); else - t->Set( v8::String::New( "_options" ) , Number::New( 0 ) ); + t->Set( scope->getV8Str( "_options" ) , Number::New( 0 ) ); - t->Set( v8::String::New( "_cursor" ) , v8::Null() ); - t->Set( v8::String::New( "_numReturned" ) , v8::Number::New(0) ); - t->Set( v8::String::New( "_special" ) , Boolean::New(false) ); + t->Set( scope->getV8Str( "_cursor" ) , v8::Null() ); + t->Set( scope->getV8Str( "_numReturned" ) , v8::Number::New(0) ); + t->Set( scope->getV8Str( "_special" ) , Boolean::New(false) ); return v8::Undefined(); } @@ -560,11 +612,11 @@ namespace mongo { return f->Call( info.This() , 1 , argv ); } - v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> objectIdInit( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> it = args.This(); if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function * f = getObjectIdCons(); + v8::Function * f = scope->getObjectIdCons(); it = f->NewInstance(); } @@ -585,12 +637,12 @@ namespace mongo { oid.init( s ); } - it->Set( v8::String::New( "str" ) , v8::String::New( oid.str().c_str() ) ); + it->Set( scope->getV8Str( "str" ) , v8::String::New( oid.str().c_str() ) ); return it; } - v8::Handle<v8::Value> dbRefInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> dbRefInit( V8Scope* scope, const v8::Arguments& args ) { if (args.Length() != 2 && args.Length() != 0) { return v8::ThrowException( v8::String::New( "DBRef needs 2 arguments" ) ); @@ -599,19 +651,19 @@ namespace mongo { v8::Handle<v8::Object> it = args.This(); if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function* f = getNamedCons( "DBRef" ); + v8::Function* f = scope->getNamedCons( "DBRef" ); it = f->NewInstance(); } if ( args.Length() == 2 ) { - it->Set( v8::String::New( "$ref" ) , args[0] ); - it->Set( v8::String::New( "$id" ) , args[1] ); + it->Set( scope->getV8Str( "$ref" ) , args[0] ); + it->Set( scope->getV8Str( "$id" ) , args[1] ); } return it; } - v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> dbPointerInit( V8Scope* scope, const v8::Arguments& args ) { if (args.Length() != 2) { return v8::ThrowException( v8::String::New( "DBPointer needs 2 arguments" ) ); @@ -620,28 +672,28 @@ namespace mongo { v8::Handle<v8::Object> it = args.This(); if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function* f = getNamedCons( "DBPointer" ); + v8::Function* f = scope->getNamedCons( "DBPointer" ); it = f->NewInstance(); } - it->Set( v8::String::New( "ns" ) , args[0] ); - it->Set( v8::String::New( "id" ) , args[1] ); - it->SetHiddenValue( v8::String::New( "__DBPointer" ), v8::Number::New( 1 ) ); + it->Set( scope->getV8Str( "ns" ) , args[0] ); + it->Set( scope->getV8Str( "id" ) , args[1] ); + it->SetHiddenValue( scope->getV8Str( "__DBPointer" ), v8::Number::New( 1 ) ); return it; } - v8::Handle<v8::Value> dbTimestampInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> dbTimestampInit( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> it = args.This(); if ( args.Length() == 0 ) { - it->Set( v8::String::New( "t" ) , v8::Number::New( 0 ) ); - it->Set( v8::String::New( "i" ) , v8::Number::New( 0 ) ); + it->Set( scope->getV8Str( "t" ) , v8::Number::New( 0 ) ); + it->Set( scope->getV8Str( "i" ) , v8::Number::New( 0 ) ); } else if ( args.Length() == 2 ) { - it->Set( v8::String::New( "t" ) , args[0] ); - it->Set( v8::String::New( "i" ) , args[1] ); + it->Set( scope->getV8Str( "t" ) , args[0] ); + it->Set( scope->getV8Str( "i" ) , args[1] ); } else { return v8::ThrowException( v8::String::New( "Timestamp needs 0 or 2 arguments" ) ); @@ -653,66 +705,157 @@ namespace mongo { } - v8::Handle<v8::Value> binDataInit( const v8::Arguments& args ) { - v8::Handle<v8::Object> it = args.This(); + v8::Handle<v8::Value> binDataInit( V8Scope* scope, const v8::Arguments& args ) { + v8::Local<v8::Object> it = args.This(); - // 3 args: len, type, data + Handle<Value> type; + Handle<Value> len; + int rlen; + char* data; if (args.Length() == 3) { + // 3 args: len, type, data if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function* f = getNamedCons( "BinData" ); + v8::Function* f = scope->getNamedCons( "BinData" ); it = f->NewInstance(); } - it->Set( v8::String::New( "len" ) , args[0] ); - it->Set( v8::String::New( "type" ) , args[1] ); - it->Set( v8::String::New( "data" ), args[2] ); - it->SetHiddenValue( v8::String::New( "__BinData" ), v8::Number::New( 1 ) ); - - // 2 args: type, base64 string + len = args[0]; + rlen = len->IntegerValue(); + type = args[1]; + v8::String::Utf8Value utf( args[ 2 ] ); + char* tmp = *utf; + data = new char[rlen]; + memcpy(data, tmp, rlen); } else if ( args.Length() == 2 ) { + // 2 args: type, base64 string if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function* f = getNamedCons( "BinData" ); + v8::Function* f = scope->getNamedCons( "BinData" ); it = f->NewInstance(); } - v8::String::Utf8Value data( args[ 1 ] ); - string decoded = base64::decode( *data ); - it->Set( v8::String::New( "len" ) , v8::Number::New( decoded.length() ) ); - it->Set( v8::String::New( "type" ) , args[ 0 ] ); - it->Set( v8::String::New( "data" ), v8::String::New( decoded.data(), decoded.length() ) ); - it->SetHiddenValue( v8::String::New( "__BinData" ), v8::Number::New( 1 ) ); - + type = args[0]; + v8::String::Utf8Value utf( args[ 1 ] ); + string decoded = base64::decode( *utf ); + const char* tmp = decoded.data(); + rlen = decoded.length(); + data = new char[rlen]; + memcpy(data, tmp, rlen); + len = v8::Number::New(rlen); +// it->Set( scope->getV8Str( "data" ), v8::String::New( decoded.data(), decoded.length() ) ); } else { - return v8::ThrowException( v8::String::New( "BinData needs 3 arguments" ) ); + return v8::ThrowException( v8::String::New( "BinData needs 2 or 3 arguments" ) ); } - return it; + it->Set( scope->getV8Str( "len" ) , len ); + it->Set( scope->getV8Str( "type" ) , type ); + it->SetHiddenValue( scope->V8STR_BINDATA, v8::Number::New( 1 ) ); + Persistent<v8::Object> res = scope->wrapArrayObject(it, data); + return res; } - v8::Handle<v8::Value> binDataToString( const v8::Arguments& args ) { - - if (args.Length() != 0) { - return v8::ThrowException( v8::String::New( "toString needs 0 arguments" ) ); - } - + v8::Handle<v8::Value> binDataToString( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> it = args.This(); - int len = it->Get( v8::String::New( "len" ) )->ToInt32()->Value(); - int type = it->Get( v8::String::New( "type" ) )->ToInt32()->Value(); - v8::String::Utf8Value data( it->Get( v8::String::New( "data" ) ) ); + int len = it->Get( scope->V8STR_LEN )->Int32Value(); + int type = it->Get( scope->V8STR_TYPE )->Int32Value(); + Local<External> c = External::Cast( *(it->GetInternalField( 0 )) ); + char* data = (char*)(c->Value()); stringstream ss; ss << "BinData(" << type << ",\""; - base64::encode( ss, *data, len ); + base64::encode( ss, data, len ); ss << "\")"; string ret = ss.str(); return v8::String::New( ret.c_str() ); } - v8::Handle<v8::Value> numberLongInit( const v8::Arguments& args ) { + v8::Handle<v8::Value> binDataToBase64( V8Scope* scope, const v8::Arguments& args ) { + v8::Handle<v8::Object> it = args.This(); + int len = Handle<v8::Number>::Cast(it->Get(scope->V8STR_LEN))->Int32Value(); + Local<External> c = External::Cast( *(it->GetInternalField( 0 )) ); + char* data = (char*)(c->Value()); + stringstream ss; + base64::encode( ss, (const char *)data, len ); + return v8::String::New(ss.str().c_str()); + } + + v8::Handle<v8::Value> binDataToHex( V8Scope* scope, const v8::Arguments& args ) { + v8::Handle<v8::Object> it = args.This(); + int len = Handle<v8::Number>::Cast(it->Get(scope->V8STR_LEN))->Int32Value(); + Local<External> c = External::Cast( *(it->GetInternalField( 0 )) ); + char* data = (char*)(c->Value()); + stringstream ss; + ss.setf (ios_base::hex , ios_base::basefield); + ss.fill ('0'); + ss.setf (ios_base::right , ios_base::adjustfield); + for( int i = 0; i < len; i++ ) { + unsigned v = (unsigned char) data[i]; + ss << setw(2) << v; + } + return v8::String::New(ss.str().c_str()); + } + + static v8::Handle<v8::Value> hexToBinData( V8Scope* scope, v8::Local<v8::Object> it, int type, string hexstr ) { + int len = hexstr.length() / 2; + char* data = new char[len]; + const char* src = hexstr.c_str(); + for( int i = 0; i < 16; i++ ) { + data[i] = fromHex(src + i * 2); + } + + it->Set( scope->V8STR_LEN , v8::Number::New(len) ); + it->Set( scope->V8STR_TYPE , v8::Number::New(type) ); + it->SetHiddenValue( scope->V8STR_BINDATA, v8::Number::New( 1 ) ); + Persistent<v8::Object> res = scope->wrapArrayObject(it, data); + return res; + } + + v8::Handle<v8::Value> uuidInit( V8Scope* scope, const v8::Arguments& args ) { + if (args.Length() != 1) { + return v8::ThrowException( v8::String::New( "UUIS needs 1 argument" ) ); + } + v8::String::Utf8Value utf( args[ 0 ] ); + if( utf.length() != 32 ) { + return v8::ThrowException( v8::String::New( "UUIS string must have 32 characters" ) ); + } + + return hexToBinData(scope, args.This(), bdtUUID, *utf); + } + +// v8::Handle<v8::Value> uuidToString( V8Scope* scope, const v8::Arguments& args ) { +// v8::Handle<v8::Object> it = args.This(); +// Local<External> c = External::Cast( *(it->GetInternalField( 0 )) ); +// char* data = (char*)(c->Value()); +// +// stringstream ss; +// ss << "UUID(\"" << toHex(data, 16) << "\")"; +// return v8::String::New( ss.str().c_str() ); +// } + + v8::Handle<v8::Value> md5Init( V8Scope* scope, const v8::Arguments& args ) { + if (args.Length() != 1) { + return v8::ThrowException( v8::String::New( "MD5 needs 1 argument" ) ); + } + v8::String::Utf8Value utf( args[ 0 ] ); + if( utf.length() != 32 ) { + return v8::ThrowException( v8::String::New( "MD5 string must have 32 characters" ) ); + } + + return hexToBinData(scope, args.This(), MD5Type, *utf); + } + + v8::Handle<v8::Value> hexDataInit( V8Scope* scope, const v8::Arguments& args ) { + if (args.Length() != 2) { + return v8::ThrowException( v8::String::New( "HexData needs 2 arguments" ) ); + } + v8::String::Utf8Value utf( args[ 1 ] ); + return hexToBinData(scope, args.This(), args[0]->IntegerValue(), *utf); + } + + v8::Handle<v8::Value> numberLongInit( V8Scope* scope, const v8::Arguments& args ) { if (args.Length() != 0 && args.Length() != 1 && args.Length() != 3) { return v8::ThrowException( v8::String::New( "NumberLong needs 0, 1 or 3 arguments" ) ); @@ -721,16 +864,16 @@ namespace mongo { v8::Handle<v8::Object> it = args.This(); if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { - v8::Function* f = getNamedCons( "NumberLong" ); + v8::Function* f = scope->getNamedCons( "NumberLong" ); it = f->NewInstance(); } if ( args.Length() == 0 ) { - it->Set( v8::String::New( "floatApprox" ), v8::Number::New( 0 ) ); + it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( 0 ) ); } else if ( args.Length() == 1 ) { if ( args[ 0 ]->IsNumber() ) { - it->Set( v8::String::New( "floatApprox" ), args[ 0 ] ); + it->Set( scope->getV8Str( "floatApprox" ), args[ 0 ] ); } else { v8::String::Utf8Value data( args[ 0 ] ); @@ -745,21 +888,21 @@ namespace mongo { } unsigned long long val = n; if ( (long long)val == (long long)(double)(long long)(val) ) { - it->Set( v8::String::New( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); + it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); } else { - it->Set( v8::String::New( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); - it->Set( v8::String::New( "top" ), v8::Integer::New( val >> 32 ) ); - it->Set( v8::String::New( "bottom" ), v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ) ); + it->Set( scope->getV8Str( "floatApprox" ), v8::Number::New( (double)(long long)( val ) ) ); + it->Set( scope->getV8Str( "top" ), v8::Integer::New( val >> 32 ) ); + it->Set( scope->getV8Str( "bottom" ), v8::Integer::New( (unsigned long)(val & 0x00000000ffffffff) ) ); } } } else { - it->Set( v8::String::New( "floatApprox" ) , args[0] ); - it->Set( v8::String::New( "top" ) , args[1] ); - it->Set( v8::String::New( "bottom" ) , args[2] ); + it->Set( scope->getV8Str( "floatApprox" ) , args[0] ); + it->Set( scope->getV8Str( "top" ) , args[1] ); + it->Set( scope->getV8Str( "bottom" ) , args[2] ); } - it->SetHiddenValue( v8::String::New( "__NumberLong" ), v8::Number::New( 1 ) ); + it->SetHiddenValue( scope->V8STR_NUMBERLONG, v8::Number::New( 1 ) ); return it; } @@ -773,29 +916,17 @@ namespace mongo { (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() ); } - v8::Handle<v8::Value> numberLongValueOf( const v8::Arguments& args ) { - - if (args.Length() != 0) { - return v8::ThrowException( v8::String::New( "toNumber needs 0 arguments" ) ); - } - + v8::Handle<v8::Value> numberLongValueOf( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> it = args.This(); - long long val = numberLongVal( it ); - return v8::Number::New( double( val ) ); } - v8::Handle<v8::Value> numberLongToNumber( const v8::Arguments& args ) { - return numberLongValueOf( args ); + v8::Handle<v8::Value> numberLongToNumber( V8Scope* scope, const v8::Arguments& args ) { + return numberLongValueOf( scope, args ); } - v8::Handle<v8::Value> numberLongToString( const v8::Arguments& args ) { - - if (args.Length() != 0) { - return v8::ThrowException( v8::String::New( "toString needs 0 arguments" ) ); - } - + v8::Handle<v8::Value> numberLongToString( V8Scope* scope, const v8::Arguments& args ) { v8::Handle<v8::Object> it = args.This(); stringstream ss; @@ -811,18 +942,62 @@ namespace mongo { return v8::String::New( ret.c_str() ); } - v8::Handle<v8::Value> bsonsize( const v8::Arguments& args ) { + v8::Handle<v8::Value> numberIntInit( V8Scope* scope, const v8::Arguments& args ) { + + if (args.Length() != 0 && args.Length() != 1) { + return v8::ThrowException( v8::String::New( "NumberInt needs 0, 1 argument" ) ); + } + + v8::Handle<v8::Object> it = args.This(); + + if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) { + v8::Function* f = scope->getNamedCons( "NumberInt" ); + it = f->NewInstance(); + } + + if ( args.Length() == 0 ) { + it->SetHiddenValue( scope->V8STR_NUMBERINT, v8::Number::New( 0 ) ); + } + else if ( args.Length() == 1 ) { + it->SetHiddenValue( scope->V8STR_NUMBERINT, args[0]->ToInt32() ); + } + + return it; + } + + v8::Handle<v8::Value> numberIntValueOf( V8Scope* scope, const v8::Arguments& args ) { + v8::Handle<v8::Object> it = args.This(); + int val = it->GetHiddenValue( scope->V8STR_NUMBERINT )->Int32Value(); + return v8::Number::New( double( val ) ); + } + + v8::Handle<v8::Value> numberIntToNumber( V8Scope* scope, const v8::Arguments& args ) { + return numberIntValueOf( scope, args ); + } + + v8::Handle<v8::Value> numberIntToString( V8Scope* scope, const v8::Arguments& args ) { + v8::Handle<v8::Object> it = args.This(); + + stringstream ss; + int val = it->GetHiddenValue( scope->V8STR_NUMBERINT )->Int32Value(); + ss << "NumberInt(" << val << ")"; + + string ret = ss.str(); + return v8::String::New( ret.c_str() ); + } + + v8::Handle<v8::Value> bsonsize( V8Scope* scope, const v8::Arguments& args ) { if ( args.Length() != 1 ) - return v8::ThrowException( v8::String::New( "bonsisze needs 1 argument" ) ); + return v8::ThrowException( v8::String::New( "bsonsize needs 1 argument" ) ); if ( args[0]->IsNull() ) return v8::Number::New(0); if ( ! args[ 0 ]->IsObject() ) - return v8::ThrowException( v8::String::New( "argument to bonsisze has to be an object" ) ); + return v8::ThrowException( v8::String::New( "argument to bsonsize has to be an object" ) ); - return v8::Number::New( v8ToMongo( args[ 0 ]->ToObject() ).objsize() ); + return v8::Number::New( scope->v8ToMongo( args[ 0 ]->ToObject() ).objsize() ); } // to be called with v8 mutex |