diff options
author | Eliot Horowitz <eliot@10gen.com> | 2009-10-13 10:12:44 -0400 |
---|---|---|
committer | Eliot Horowitz <eliot@10gen.com> | 2009-10-13 10:12:44 -0400 |
commit | fe88b0695996ba2f098c513ad26b7cdcc63e8b79 (patch) | |
tree | 657b1de058a452d5f344a257ef3d2a20f112f060 /scripting | |
parent | 5f62314f9e34c4ecba6f4ad328c2bb90a68d0447 (diff) | |
download | mongo-fe88b0695996ba2f098c513ad26b7cdcc63e8b79.tar.gz |
v8: refactoring checkpoint
Diffstat (limited to 'scripting')
-rw-r--r-- | scripting/engine_v8.cpp | 82 | ||||
-rw-r--r-- | scripting/engine_v8.h | 14 | ||||
-rw-r--r-- | scripting/v8_db.cpp | 388 | ||||
-rw-r--r-- | scripting/v8_db.h | 43 | ||||
-rw-r--r-- | scripting/v8_wrapper.cpp | 371 | ||||
-rw-r--r-- | scripting/v8_wrapper.h | 40 |
6 files changed, 522 insertions, 416 deletions
diff --git a/scripting/engine_v8.cpp b/scripting/engine_v8.cpp index e85d563b158..1bd9bd9a65a 100644 --- a/scripting/engine_v8.cpp +++ b/scripting/engine_v8.cpp @@ -29,7 +29,8 @@ namespace mongo { : _handleScope(), _context( Context::New( 0 , engine->_globalTemplate ) ) , _scope( _context ) , - _global( _context->Global() ){ + _global( _context->Global() ) , + _connectState( NOT ){ _this = v8::Object::New(); } @@ -57,6 +58,19 @@ namespace mongo { return mongoToV8Element( ret.firstElement() ); } + // ---- global stuff ---- + + void V8Scope::init( BSONObj * data ){ + if ( ! data ) + return; + + BSONObjIterator i( *data ); + while ( i.more() ){ + BSONElement e = i.next(); + setElement( e.fieldName() , e ); + } + } + void V8Scope::setNumber( const char * field , double val ){ _global->Set( v8::String::New( field ) , v8::Number::New( val ) ); } @@ -78,8 +92,34 @@ namespace mongo { _global->Set( v8::String::New( field ) , mongoToV8( obj ) ); } - void V8Scope::setThis( const BSONObj * obj ){ - _this = mongoToV8( *obj ); + int V8Scope::type( const char *field ){ + Handle<Value> v = get( field ); + if ( v->IsNull() ) + return jstNULL; + if ( v->IsUndefined() ) + return Undefined; + if ( v->IsString() ) + return String; + if ( v->IsFunction() ) + return Code; + if ( v->IsArray() ) + return Array; + if ( v->IsObject() ) + return Object; + if ( v->IsBoolean() ) + return Bool; + if ( v->IsInt32() ) + return NumberInt; + if ( v->IsNumber() ) + return NumberDouble; + if ( v->IsExternal() ){ + uassert( "can't handle external yet" , 0 ); + return -1; + } + if ( v->IsDate() ) + return Date; + + throw UserException( (string)"don't know what this is: " + field ); } v8::Handle<v8::Value> V8Scope::get( const char * field ){ @@ -97,7 +137,7 @@ namespace mongo { bool V8Scope::getBoolean( const char *field ){ return get( field )->ToBoolean()->Value(); } - + BSONObj V8Scope::getObject( const char * field ){ Handle<Value> v = get( field ); if ( v->IsNull() || v->IsUndefined() ) @@ -105,6 +145,8 @@ namespace mongo { uassert( "not an object" , v->IsObject() ); return v8ToMongo( v->ToObject() ); } + + // --- functions ----- ScriptingFunction V8Scope::_createFunction( const char * raw ){ @@ -150,6 +192,10 @@ namespace mongo { _funcs.push_back( f ); return num; } + + void V8Scope::setThis( const BSONObj * obj ){ + _this = mongoToV8( *obj ); + } int V8Scope::invoke( ScriptingFunction func , const BSONObj& argsObject, int timeoutMs , bool ignoreReturn ){ Handle<Value> funcValue = _funcs[func-1]; @@ -227,6 +273,34 @@ namespace mongo { return true; } + // ----- db access ----- + + void V8Scope::localConnect( const char * dbName ){ + if ( _connectState == EXTERNAL ) + throw UserException( "externalSetup already called, can't call externalSetup" ); + if ( _connectState == LOCAL ){ + if ( _localDBName == dbName ) + return; + throw UserException( "localConnect called with a different name previously" ); + } + + uassert( "local connect not supported yet" , 0 ); + _connectState = LOCAL; + } + + void V8Scope::externalSetup(){ + if ( _connectState == EXTERNAL ) + return; + if ( _connectState == LOCAL ) + throw UserException( "localConnect already called, can't call externalSetup" ); + + + uassert( "externalSetup not supported yet" , 0 ); + _connectState = EXTERNAL; + } + + // ----- internal ----- + void V8Scope::_startCall(){ _error = ""; } diff --git a/scripting/engine_v8.h b/scripting/engine_v8.h index ade97b777be..205dd8f8ba0 100644 --- a/scripting/engine_v8.h +++ b/scripting/engine_v8.h @@ -17,10 +17,10 @@ namespace mongo { ~V8Scope(); virtual void reset(){} - virtual void init( BSONObj * data ){ assert(0); } + virtual void init( BSONObj * data ); - virtual void localConnect( const char * dbName ){ assert(0); } - virtual void externalSetup(){ assert(0); }; + virtual void localConnect( const char * dbName ); + virtual void externalSetup(); v8::Handle<v8::Value> get( const char * field ); virtual double getNumber( const char *field ); @@ -28,7 +28,7 @@ namespace mongo { virtual bool getBoolean( const char *field ); virtual BSONObj getObject( const char *field ); - virtual int type( const char *field ){ assert( false ); return 0; } + virtual int type( const char *field ); virtual void setNumber( const char *field , double val ); virtual void setString( const char *field , const char * val ); @@ -48,7 +48,7 @@ namespace mongo { _global->Set( v8::String::New( field ), f->GetFunction() ); } - void gc(){ assert(0); } + void gc(){} // no-op in v8 private: void _startCall(); @@ -63,6 +63,10 @@ namespace mongo { string _error; vector< v8::Handle<Value> > _funcs; v8::Handle<v8::Object> _this; + + enum ConnectState { NOT , LOCAL , EXTERNAL }; + ConnectState _connectState; + string _localDBName; }; class V8ScriptEngine : public ScriptEngine { diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp new file mode 100644 index 00000000000..6eb533fc82d --- /dev/null +++ b/scripting/v8_db.cpp @@ -0,0 +1,388 @@ +// v8_db.cpp + +#include "v8_wrapper.h" +#include "v8_utils.h" +#include "v8_db.h" + +#include <iostream> + +using namespace std; +using namespace v8; + +namespace mongo { + +#define CONN_STRING (v8::String::New( "_conn" )) + +#define DDD(x) + + void installMongoGlobals( Handle<ObjectTemplate>& global ){ + global->Set(v8::String::New("mongoInject"), FunctionTemplate::New(mongoInject)); + + v8::Local<v8::FunctionTemplate> mongo = FunctionTemplate::New( mongoInit ); + global->Set(v8::String::New("Mongo") , mongo ); + + v8::Local<v8::FunctionTemplate> db = FunctionTemplate::New( dbInit ); + global->Set(v8::String::New("DB") , db ); + db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); + + v8::Local<v8::FunctionTemplate> dbCollection = FunctionTemplate::New( collectionInit ); + global->Set(v8::String::New("DBCollection") , dbCollection ); + dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); + + v8::Local<v8::FunctionTemplate> dbQuery = FunctionTemplate::New( dbQueryInit ); + global->Set(v8::String::New("DBQuery") , dbQuery ); + dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess ); + + v8::Local<v8::FunctionTemplate> objectId = FunctionTemplate::New( objectIdInit ); + global->Set(v8::String::New("ObjectId") , objectId ); + } + + Handle<Value> mongoInject(const Arguments& args){ + jsassert( args.Length() == 1 , "mongoInject takes exactly 1 argument" ); + jsassert( args[0]->IsObject() , "mongoInject needs to be passed a prototype" ); + + Local<v8::Object> o = args[0]->ToObject(); + + o->Set( v8::String::New( "init" ) , FunctionTemplate::New( mongoInit )->GetFunction() ); + o->Set( v8::String::New( "find" ) , FunctionTemplate::New( mongoFind )->GetFunction() ); + o->Set( v8::String::New( "insert" ) , FunctionTemplate::New( mongoInsert )->GetFunction() ); + o->Set( v8::String::New( "remove" ) , FunctionTemplate::New( mongoRemove )->GetFunction() ); + o->Set( v8::String::New( "update" ) , FunctionTemplate::New( mongoUpdate )->GetFunction() ); + + Local<FunctionTemplate> t = FunctionTemplate::New( internalCursorCons ); + t->PrototypeTemplate()->Set( v8::String::New("next") , FunctionTemplate::New( internalCursorNext ) ); + t->PrototypeTemplate()->Set( v8::String::New("hasNext") , FunctionTemplate::New( internalCursorHasNext ) ); + o->Set( v8::String::New( "internalCursor" ) , t->GetFunction() ); + + return v8::Undefined(); + } + + Handle<Value> mongoInit(const Arguments& args){ + + char host[255]; + + if ( args.Length() > 0 && args[0]->IsString() ){ + assert( args[0]->ToString()->Utf8Length() < 250 ); + args[0]->ToString()->WriteAscii( host ); + } + else { + strcpy( host , "127.0.0.1" ); + } + + DBClientConnection * conn = new DBClientConnection( true ); + + string errmsg; + if ( ! conn->connect( host , errmsg ) ){ + return v8::ThrowException( v8::String::New( "couldn't connect" ) ); + } + + // NOTE I don't believe the conn object will ever be freed. + args.This()->Set( CONN_STRING , External::New( conn ) ); + args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); + + return v8::Undefined(); + } + + + // --- + +#ifdef _WIN32 +#define GETNS char * ns = new char[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns ); +#else +#define GETNS char ns[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns ); +#endif + + DBClientConnection * getConnection( const Arguments& args ){ + Local<External> c = External::Cast( *(args.This()->Get( CONN_STRING )) ); + DBClientConnection * conn = (DBClientConnection*)(c->Value()); + assert( conn ); + return conn; + } + + // ---- real methods + + /** + 0 - namespace + 1 - query + 2 - fields + 3 - limit + 4 - skip + */ + Handle<Value> mongoFind(const Arguments& args){ + jsassert( args.Length() == 5 , "find needs 5 args" ); + jsassert( args[1]->IsObject() , "needs to be an object" ); + DBClientConnection * conn = getConnection( args ); + GETNS; + + BSONObj q = 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() ); + + Local<v8::Object> mongo = args.This(); + Local<v8::Value> slaveOkVal = mongo->Get( v8::String::New( "slaveOk" ) ); + jsassert( slaveOkVal->IsBoolean(), "slaveOk member invalid" ); + bool slaveOk = slaveOkVal->BooleanValue(); + + try { + auto_ptr<mongo::DBClientCursor> cursor; + int nToReturn = (int)(args[3]->ToNumber()->Value()); + int nToSkip = (int)(args[4]->ToNumber()->Value()); + { + v8::Unlocker u; + cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, slaveOk ? Option_SlaveOk : 0 ); + } + + v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) ); + Local<v8::Object> c = cons->NewInstance(); + + // NOTE I don't believe the cursor object will ever be freed. + c->Set( v8::String::New( "cursor" ) , External::New( cursor.release() ) ); + return c; + } + catch ( ... ){ + return v8::ThrowException( v8::String::New( "socket error on query" ) ); + } + } + + v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args){ + jsassert( args.Length() == 2 , "insert needs 2 args" ); + jsassert( args[1]->IsObject() , "have to insert an object" ); + + DBClientConnection * conn = getConnection( args ); + GETNS; + + v8::Handle<v8::Object> in = args[1]->ToObject(); + + if ( ! in->Has( v8::String::New( "_id" ) ) ){ + v8::Handle<v8::Value> argv[1]; + in->Set( v8::String::New( "_id" ) , getObjectIdCons()->NewInstance( 0 , argv ) ); + } + + BSONObj o = v8ToMongo( in ); + + DDD( "want to save : " << o.jsonString() ); + try { + conn->insert( ns , o ); + } + catch ( ... ){ + return v8::ThrowException( v8::String::New( "socket error on insert" ) ); + } + + return args[1]; + } + + v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args){ + jsassert( args.Length() == 2 , "remove needs 2 args" ); + jsassert( args[1]->IsObject() , "have to remove an object template" ); + + DBClientConnection * conn = getConnection( args ); + GETNS; + + v8::Handle<v8::Object> in = args[1]->ToObject(); + BSONObj o = v8ToMongo( in ); + + DDD( "want to remove : " << o.jsonString() ); + try { + conn->remove( ns , o ); + } + catch ( ... ){ + return v8::ThrowException( v8::String::New( "socket error on remove" ) ); + } + + return v8::Undefined(); + } + + v8::Handle<v8::Value> mongoUpdate(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" ); + + DBClientConnection * conn = getConnection( args ); + GETNS; + + v8::Handle<v8::Object> q = args[1]->ToObject(); + v8::Handle<v8::Object> o = args[2]->ToObject(); + + bool upsert = args.Length() > 3 && args[3]->IsBoolean() && args[3]->ToBoolean()->Value(); + + try { + conn->update( ns , v8ToMongo( q ) , v8ToMongo( o ) , upsert ); + } + catch ( ... ){ + return v8::ThrowException( v8::String::New( "socket error on remove" ) ); + } + + return v8::Undefined(); + } + + + + + // --- cursor --- + + mongo::DBClientCursor * getCursor( const Arguments& args ){ + Local<External> c = External::Cast( *(args.This()->Get( v8::String::New( "cursor" ) ) ) ); + mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value()); + return cursor; + } + + v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args){ + return v8::Undefined(); + } + + v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args){ + mongo::DBClientCursor * cursor = getCursor( args ); + if ( ! cursor ) + return v8::Undefined(); + BSONObj o; + { + v8::Unlocker u; + o = cursor->next(); + } + return mongoToV8( o ); + } + + v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args){ + mongo::DBClientCursor * cursor = getCursor( args ); + if ( ! cursor ) + return Boolean::New( false ); + bool more; + { + v8::Unlocker u; + more = cursor->more(); + } + return Boolean::New( more ); + } + + + // --- DB ---- + + v8::Handle<v8::Value> dbInit(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] ); + + for ( int i=0; i<args.Length(); i++ ) + assert( ! args[i]->IsUndefined() ); + + return v8::Undefined(); + } + + v8::Handle<v8::Value> collectionInit( 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] ); + + for ( int i=0; i<args.Length(); i++ ) + assert( ! args[i]->IsUndefined() ); + + return v8::Undefined(); + } + + v8::Handle<v8::Value> dbQueryInit( 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] ); + + if ( args.Length() > 4 && args[4]->IsObject() ) + t->Set( v8::String::New( "_query" ) , args[4] ); + else + t->Set( v8::String::New( "_query" ) , v8::Object::New() ); + + if ( args.Length() > 5 && args[5]->IsObject() ) + t->Set( v8::String::New( "_fields" ) , args[5] ); + else + t->Set( v8::String::New( "_fields" ) , v8::Null() ); + + + if ( args.Length() > 6 && args[6]->IsNumber() ) + t->Set( v8::String::New( "_limit" ) , args[6] ); + else + t->Set( v8::String::New( "_limit" ) , Number::New( 0 ) ); + + if ( args.Length() > 7 && args[7]->IsNumber() ) + t->Set( v8::String::New( "_skip" ) , args[7] ); + else + t->Set( v8::String::New( "_skip" ) , 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) ); + + return v8::Undefined(); + } + + v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info) { + DDD( "collectionFallback [" << name << "]" ); + + v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get( name ); + if ( ! real->IsUndefined() ) + return real; + + string sname = toSTLString( name ); + if ( sname[0] == '_' ){ + if ( ! ( info.This()->HasRealNamedProperty( name ) ) ) + return v8::Undefined(); + return info.This()->GetRealNamedPropertyInPrototypeChain( name ); + } + + v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "getCollection" ) ); + assert( getCollection->IsFunction() ); + + v8::Function * f = (v8::Function*)(*getCollection); + v8::Handle<v8::Value> argv[1]; + argv[0] = name; + + return f->Call( info.This() , 1 , argv ); + } + + v8::Handle<v8::Value> dbQueryIndexAccess( unsigned int index , const v8::AccessorInfo& info ){ + v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "arrayAccess" ) ); + assert( arrayAccess->IsFunction() ); + + v8::Function * f = (v8::Function*)(*arrayAccess); + v8::Handle<v8::Value> argv[1]; + argv[0] = v8::Number::New( index ); + + return f->Call( info.This() , 1 , argv ); + } + + v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ){ + v8::Handle<v8::Object> it = args.This(); + + if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){ + v8::Function * f = getObjectIdCons(); + it = f->NewInstance(); + } + + OID oid; + + if ( args.Length() == 0 ){ + oid.init(); + } + else { + string s = toSTLString( args[0] ); + oid.init( s ); + } + + it->Set( v8::String::New( "str" ) , v8::String::New( oid.str().c_str() ) ); + + return it; + } + + +} diff --git a/scripting/v8_db.h b/scripting/v8_db.h new file mode 100644 index 00000000000..1692396b625 --- /dev/null +++ b/scripting/v8_db.h @@ -0,0 +1,43 @@ +// v8_db.h + +#pragma once + +#include <v8.h> +#include <cstring> +#include <cstdio> +#include <cstdlib> + +#include "../client/dbclient.h" + +namespace mongo { + void installMongoGlobals( v8::Handle<v8::ObjectTemplate>& global ); + + // the actual globals + v8::Handle<v8::Value> mongoInject(const v8::Arguments& args); + + mongo::DBClientConnection * getConnection( const v8::Arguments& args ); + + // Mongo members + v8::Handle<v8::Value> mongoInit(const v8::Arguments& args); + v8::Handle<v8::Value> mongoFind(const v8::Arguments& args); + v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args); + v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args); + v8::Handle<v8::Value> mongoUpdate(const v8::Arguments& args); + + + v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args); + v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args); + v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args); + + // DB members + + v8::Handle<v8::Value> dbInit(const v8::Arguments& args); + v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ); + v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ); + + v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ); + v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info ); + + v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info); + +} diff --git a/scripting/v8_wrapper.cpp b/scripting/v8_wrapper.cpp index e98d3316932..4d101514414 100644 --- a/scripting/v8_wrapper.cpp +++ b/scripting/v8_wrapper.cpp @@ -13,78 +13,6 @@ namespace mongo { #define CONN_STRING (v8::String::New( "_conn" )) #define DDD(x) - //#define DDD(x) ( cout << x << endl ); - - void installMongoGlobals( Handle<ObjectTemplate>& global ){ - global->Set(v8::String::New("mongoInject"), FunctionTemplate::New(mongoInject)); - - v8::Local<v8::FunctionTemplate> mongo = FunctionTemplate::New( mongoInit ); - global->Set(v8::String::New("Mongo") , mongo ); - - v8::Local<v8::FunctionTemplate> db = FunctionTemplate::New( dbInit ); - global->Set(v8::String::New("DB") , db ); - db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - - v8::Local<v8::FunctionTemplate> dbCollection = FunctionTemplate::New( collectionInit ); - global->Set(v8::String::New("DBCollection") , dbCollection ); - dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback ); - - v8::Local<v8::FunctionTemplate> dbQuery = FunctionTemplate::New( dbQueryInit ); - global->Set(v8::String::New("DBQuery") , dbQuery ); - dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess ); - - v8::Local<v8::FunctionTemplate> objectId = FunctionTemplate::New( objectIdInit ); - global->Set(v8::String::New("ObjectId") , objectId ); - } - - Handle<Value> mongoInject(const Arguments& args){ - jsassert( args.Length() == 1 , "mongoInject takes exactly 1 argument" ); - jsassert( args[0]->IsObject() , "mongoInject needs to be passed a prototype" ); - - Local<v8::Object> o = args[0]->ToObject(); - - o->Set( v8::String::New( "init" ) , FunctionTemplate::New( mongoInit )->GetFunction() ); - o->Set( v8::String::New( "find" ) , FunctionTemplate::New( mongoFind )->GetFunction() ); - o->Set( v8::String::New( "insert" ) , FunctionTemplate::New( mongoInsert )->GetFunction() ); - o->Set( v8::String::New( "remove" ) , FunctionTemplate::New( mongoRemove )->GetFunction() ); - o->Set( v8::String::New( "update" ) , FunctionTemplate::New( mongoUpdate )->GetFunction() ); - - Local<FunctionTemplate> t = FunctionTemplate::New( internalCursorCons ); - t->PrototypeTemplate()->Set( v8::String::New("next") , FunctionTemplate::New( internalCursorNext ) ); - t->PrototypeTemplate()->Set( v8::String::New("hasNext") , FunctionTemplate::New( internalCursorHasNext ) ); - o->Set( v8::String::New( "internalCursor" ) , t->GetFunction() ); - - return v8::Undefined(); - } - - Handle<Value> mongoInit(const Arguments& args){ - - char host[255]; - - if ( args.Length() > 0 && args[0]->IsString() ){ - assert( args[0]->ToString()->Utf8Length() < 250 ); - args[0]->ToString()->WriteAscii( host ); - } - else { - strcpy( host , "127.0.0.1" ); - } - - DBClientConnection * conn = new DBClientConnection( true ); - - string errmsg; - if ( ! conn->connect( host , errmsg ) ){ - return v8::ThrowException( v8::String::New( "couldn't connect" ) ); - } - - // NOTE I don't believe the conn object will ever be freed. - args.This()->Set( CONN_STRING , External::New( conn ) ); - args.This()->Set( v8::String::New( "slaveOk" ) , Boolean::New( false ) ); - - return v8::Undefined(); - } - - - // --- Local<v8::Object> mongoToV8( const BSONObj& m , bool array ){ Local<v8::Object> o; @@ -382,281 +310,6 @@ namespace mongo { return b.obj(); } -#ifdef _WIN32 -#define GETNS char * ns = new char[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns ); -#else -#define GETNS char ns[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns ); -#endif - - DBClientConnection * getConnection( const Arguments& args ){ - Local<External> c = External::Cast( *(args.This()->Get( CONN_STRING )) ); - DBClientConnection * conn = (DBClientConnection*)(c->Value()); - assert( conn ); - return conn; - } - - // ---- real methods - - /** - 0 - namespace - 1 - query - 2 - fields - 3 - limit - 4 - skip - */ - Handle<Value> mongoFind(const Arguments& args){ - jsassert( args.Length() == 5 , "find needs 5 args" ); - jsassert( args[1]->IsObject() , "needs to be an object" ); - DBClientConnection * conn = getConnection( args ); - GETNS; - - BSONObj q = 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() ); - - Local<v8::Object> mongo = args.This(); - Local<v8::Value> slaveOkVal = mongo->Get( v8::String::New( "slaveOk" ) ); - jsassert( slaveOkVal->IsBoolean(), "slaveOk member invalid" ); - bool slaveOk = slaveOkVal->BooleanValue(); - - try { - auto_ptr<mongo::DBClientCursor> cursor; - int nToReturn = (int)(args[3]->ToNumber()->Value()); - int nToSkip = (int)(args[4]->ToNumber()->Value()); - { - v8::Unlocker u; - cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, slaveOk ? Option_SlaveOk : 0 ); - } - - v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) ); - Local<v8::Object> c = cons->NewInstance(); - - // NOTE I don't believe the cursor object will ever be freed. - c->Set( v8::String::New( "cursor" ) , External::New( cursor.release() ) ); - return c; - } - catch ( ... ){ - return v8::ThrowException( v8::String::New( "socket error on query" ) ); - } - } - - v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args){ - jsassert( args.Length() == 2 , "insert needs 2 args" ); - jsassert( args[1]->IsObject() , "have to insert an object" ); - - DBClientConnection * conn = getConnection( args ); - GETNS; - - v8::Handle<v8::Object> in = args[1]->ToObject(); - - if ( ! in->Has( v8::String::New( "_id" ) ) ){ - v8::Handle<v8::Value> argv[1]; - in->Set( v8::String::New( "_id" ) , getObjectIdCons()->NewInstance( 0 , argv ) ); - } - - BSONObj o = v8ToMongo( in ); - - DDD( "want to save : " << o.jsonString() ); - try { - conn->insert( ns , o ); - } - catch ( ... ){ - return v8::ThrowException( v8::String::New( "socket error on insert" ) ); - } - - return args[1]; - } - - v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args){ - jsassert( args.Length() == 2 , "remove needs 2 args" ); - jsassert( args[1]->IsObject() , "have to remove an object template" ); - - DBClientConnection * conn = getConnection( args ); - GETNS; - - v8::Handle<v8::Object> in = args[1]->ToObject(); - BSONObj o = v8ToMongo( in ); - - DDD( "want to remove : " << o.jsonString() ); - try { - conn->remove( ns , o ); - } - catch ( ... ){ - return v8::ThrowException( v8::String::New( "socket error on remove" ) ); - } - - return v8::Undefined(); - } - - v8::Handle<v8::Value> mongoUpdate(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" ); - - DBClientConnection * conn = getConnection( args ); - GETNS; - - v8::Handle<v8::Object> q = args[1]->ToObject(); - v8::Handle<v8::Object> o = args[2]->ToObject(); - - bool upsert = args.Length() > 3 && args[3]->IsBoolean() && args[3]->ToBoolean()->Value(); - - try { - conn->update( ns , v8ToMongo( q ) , v8ToMongo( o ) , upsert ); - } - catch ( ... ){ - return v8::ThrowException( v8::String::New( "socket error on remove" ) ); - } - - return v8::Undefined(); - } - - - - - // --- cursor --- - - mongo::DBClientCursor * getCursor( const Arguments& args ){ - Local<External> c = External::Cast( *(args.This()->Get( v8::String::New( "cursor" ) ) ) ); - mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value()); - return cursor; - } - - v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args){ - return v8::Undefined(); - } - - v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args){ - mongo::DBClientCursor * cursor = getCursor( args ); - if ( ! cursor ) - return v8::Undefined(); - BSONObj o; - { - v8::Unlocker u; - o = cursor->next(); - } - return mongoToV8( o ); - } - - v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args){ - mongo::DBClientCursor * cursor = getCursor( args ); - if ( ! cursor ) - return Boolean::New( false ); - bool more; - { - v8::Unlocker u; - more = cursor->more(); - } - return Boolean::New( more ); - } - - - // --- DB ---- - - v8::Handle<v8::Value> dbInit(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] ); - - for ( int i=0; i<args.Length(); i++ ) - assert( ! args[i]->IsUndefined() ); - - return v8::Undefined(); - } - - v8::Handle<v8::Value> collectionInit( 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] ); - - for ( int i=0; i<args.Length(); i++ ) - assert( ! args[i]->IsUndefined() ); - - return v8::Undefined(); - } - - v8::Handle<v8::Value> dbQueryInit( 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] ); - - if ( args.Length() > 4 && args[4]->IsObject() ) - t->Set( v8::String::New( "_query" ) , args[4] ); - else - t->Set( v8::String::New( "_query" ) , v8::Object::New() ); - - if ( args.Length() > 5 && args[5]->IsObject() ) - t->Set( v8::String::New( "_fields" ) , args[5] ); - else - t->Set( v8::String::New( "_fields" ) , v8::Null() ); - - - if ( args.Length() > 6 && args[6]->IsNumber() ) - t->Set( v8::String::New( "_limit" ) , args[6] ); - else - t->Set( v8::String::New( "_limit" ) , Number::New( 0 ) ); - - if ( args.Length() > 7 && args[7]->IsNumber() ) - t->Set( v8::String::New( "_skip" ) , args[7] ); - else - t->Set( v8::String::New( "_skip" ) , 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) ); - - return v8::Undefined(); - } - - v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info) { - DDD( "collectionFallback [" << name << "]" ); - - v8::Handle<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get( name ); - if ( ! real->IsUndefined() ) - return real; - - string sname = toSTLString( name ); - if ( sname[0] == '_' ){ - if ( ! ( info.This()->HasRealNamedProperty( name ) ) ) - return v8::Undefined(); - return info.This()->GetRealNamedPropertyInPrototypeChain( name ); - } - - v8::Handle<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "getCollection" ) ); - assert( getCollection->IsFunction() ); - - v8::Function * f = (v8::Function*)(*getCollection); - v8::Handle<v8::Value> argv[1]; - argv[0] = name; - - return f->Call( info.This() , 1 , argv ); - } - - v8::Handle<v8::Value> dbQueryIndexAccess( unsigned int index , const v8::AccessorInfo& info ){ - v8::Handle<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get( v8::String::New( "arrayAccess" ) ); - assert( arrayAccess->IsFunction() ); - - v8::Function * f = (v8::Function*)(*arrayAccess); - v8::Handle<v8::Value> argv[1]; - argv[0] = v8::Number::New( index ); - - return f->Call( info.This() , 1 , argv ); - } - v8::Function * getNamedCons( const char * name ){ return v8::Function::Cast( *(v8::Context::GetCurrent()->Global()->Get( v8::String::New( name ) ) ) ); } @@ -665,28 +318,4 @@ namespace mongo { return getNamedCons( "ObjectId" ); } - v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ){ - v8::Handle<v8::Object> it = args.This(); - - if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){ - v8::Function * f = getObjectIdCons(); - it = f->NewInstance(); - } - - OID oid; - - if ( args.Length() == 0 ){ - oid.init(); - } - else { - string s = toSTLString( args[0] ); - oid.init( s ); - } - - it->Set( v8::String::New( "str" ) , v8::String::New( oid.str().c_str() ) ); - - return it; - } - - } diff --git a/scripting/v8_wrapper.h b/scripting/v8_wrapper.h index 2f41822ae41..4719bb9135a 100644 --- a/scripting/v8_wrapper.h +++ b/scripting/v8_wrapper.h @@ -6,49 +6,17 @@ #include <cstring> #include <cstdio> #include <cstdlib> - -#include "../client/dbclient.h" +#include "../db/jsobj.h" namespace mongo { - void installMongoGlobals( v8::Handle<v8::ObjectTemplate>& global ); - - // the actual globals - v8::Handle<v8::Value> mongoInject(const v8::Arguments& args); - - // utils + v8::Local<v8::Object> mongoToV8( const mongo::BSONObj & m , bool array = 0 ); mongo::BSONObj v8ToMongo( v8::Handle<v8::Object> o ); - 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 ); v8::Handle<v8::Value> mongoToV8Element( const BSONElement &f ); - mongo::DBClientConnection * getConnection( const v8::Arguments& args ); - - - - // Mongo members - v8::Handle<v8::Value> mongoInit(const v8::Arguments& args); - v8::Handle<v8::Value> mongoFind(const v8::Arguments& args); - v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args); - v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args); - v8::Handle<v8::Value> mongoUpdate(const v8::Arguments& args); - - - v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args); - v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args); - v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args); - - // DB members - - v8::Handle<v8::Value> dbInit(const v8::Arguments& args); - v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ); - v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ); - - v8::Handle<v8::Value> dbQueryInit( const v8::Arguments& args ); - v8::Handle<v8::Value> dbQueryIndexAccess( uint32_t index , const v8::AccessorInfo& info ); - - v8::Handle<v8::Value> collectionFallback( v8::Local<v8::String> name, const v8::AccessorInfo &info); - v8::Function * getNamedCons( const char * name ); v8::Function * getObjectIdCons(); |