summaryrefslogtreecommitdiff
path: root/scripting
diff options
context:
space:
mode:
authorEliot Horowitz <eliot@10gen.com>2009-10-13 10:12:44 -0400
committerEliot Horowitz <eliot@10gen.com>2009-10-13 10:12:44 -0400
commitfe88b0695996ba2f098c513ad26b7cdcc63e8b79 (patch)
tree657b1de058a452d5f344a257ef3d2a20f112f060 /scripting
parent5f62314f9e34c4ecba6f4ad328c2bb90a68d0447 (diff)
downloadmongo-fe88b0695996ba2f098c513ad26b7cdcc63e8b79.tar.gz
v8: refactoring checkpoint
Diffstat (limited to 'scripting')
-rw-r--r--scripting/engine_v8.cpp82
-rw-r--r--scripting/engine_v8.h14
-rw-r--r--scripting/v8_db.cpp388
-rw-r--r--scripting/v8_db.h43
-rw-r--r--scripting/v8_wrapper.cpp371
-rw-r--r--scripting/v8_wrapper.h40
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();