summaryrefslogtreecommitdiff
path: root/scripting/v8_db.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scripting/v8_db.cpp')
-rw-r--r--scripting/v8_db.cpp498
1 files changed, 315 insertions, 183 deletions
diff --git a/scripting/v8_db.cpp b/scripting/v8_db.cpp
index e178875..4d12454 100644
--- a/scripting/v8_db.cpp
+++ b/scripting/v8_db.cpp
@@ -18,10 +18,11 @@
#include "v8_wrapper.h"
#include "v8_utils.h"
#include "v8_db.h"
-#include "engine.h"
+#include "engine_v8.h"
#include "util/base64.h"
#include "util/text.h"
#include "../client/syncclusterconnection.h"
+#include "../s/d_logic.h"
#include <iostream>
using namespace std;
@@ -31,99 +32,118 @@ namespace mongo {
#define DDD(x)
- v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ){
- v8::Local<v8::FunctionTemplate> mongo = FunctionTemplate::New( local ? mongoConsLocal : mongoConsExternal );
+ v8::Handle<v8::FunctionTemplate> getMongoFunctionTemplate( bool local ) {
+ v8::Local<v8::FunctionTemplate> mongo;
+ if ( local ) {
+ mongo = newV8Function< mongoConsLocal >();
+ }
+ else {
+ mongo = newV8Function< mongoConsExternal >();
+ }
mongo->InstanceTemplate()->SetInternalFieldCount( 1 );
-
+
v8::Local<v8::Template> proto = mongo->PrototypeTemplate();
- proto->Set( v8::String::New( "find" ) , FunctionTemplate::New( mongoFind ) );
- proto->Set( v8::String::New( "insert" ) , FunctionTemplate::New( mongoInsert ) );
- proto->Set( v8::String::New( "remove" ) , FunctionTemplate::New( mongoRemove ) );
- proto->Set( v8::String::New( "update" ) , FunctionTemplate::New( mongoUpdate ) );
+ 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 = FunctionTemplate::New( internalCursorCons );
+ Local<FunctionTemplate> ic = newV8Function< internalCursorCons >();
ic->InstanceTemplate()->SetInternalFieldCount( 1 );
- ic->PrototypeTemplate()->Set( v8::String::New("next") , FunctionTemplate::New( internalCursorNext ) );
- ic->PrototypeTemplate()->Set( v8::String::New("hasNext") , FunctionTemplate::New( internalCursorHasNext ) );
- ic->PrototypeTemplate()->Set( v8::String::New("objsLeftInBatch") , FunctionTemplate::New( internalCursorObjsLeftInBatch ) );
+ 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 );
-
+
return mongo;
}
v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate() {
- v8::Local<v8::FunctionTemplate> numberLong = FunctionTemplate::New( numberLongInit );
+ v8::Local<v8::FunctionTemplate> numberLong = newV8Function< numberLongInit >();
v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
-
- proto->Set( v8::String::New( "valueOf" ) , FunctionTemplate::New( numberLongValueOf ) );
- proto->Set( v8::String::New( "toNumber" ) , FunctionTemplate::New( numberLongToNumber ) );
- proto->Set( v8::String::New( "toString" ) , FunctionTemplate::New( numberLongToString ) );
-
+
+ proto->Set( v8::String::New( "valueOf" ) , newV8Function< numberLongValueOf >() );
+ proto->Set( v8::String::New( "toNumber" ) , newV8Function< numberLongToNumber >() );
+ proto->Set( v8::String::New( "toString" ) , newV8Function< numberLongToString >() );
+
return numberLong;
}
v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate() {
- v8::Local<v8::FunctionTemplate> binData = FunctionTemplate::New( binDataInit );
+ v8::Local<v8::FunctionTemplate> binData = newV8Function< binDataInit >();
v8::Local<v8::Template> proto = binData->PrototypeTemplate();
-
- proto->Set( v8::String::New( "toString" ) , FunctionTemplate::New( binDataToString ) );
-
+
+ proto->Set( v8::String::New( "toString" ) , newV8Function< binDataToString >() );
+
return binData;
- }
-
- void installDBTypes( Handle<ObjectTemplate>& global ){
- v8::Local<v8::FunctionTemplate> db = FunctionTemplate::New( dbInit );
+ }
+
+ 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;
+ }
+
+
+ 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 = FunctionTemplate::New( collectionInit );
+
+ v8::Local<v8::FunctionTemplate> dbCollection = newV8Function< collectionInit >();
dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
global->Set(v8::String::New("DBCollection") , dbCollection );
- v8::Local<v8::FunctionTemplate> dbQuery = FunctionTemplate::New( dbQueryInit );
+ v8::Local<v8::FunctionTemplate> dbQuery = newV8Function< dbQueryInit >();
dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess );
global->Set(v8::String::New("DBQuery") , dbQuery );
- global->Set( v8::String::New("ObjectId") , FunctionTemplate::New( objectIdInit ) );
+ global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >() );
- global->Set( v8::String::New("DBRef") , FunctionTemplate::New( dbRefInit ) );
+ global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >() );
- global->Set( v8::String::New("DBPointer") , FunctionTemplate::New( dbPointerInit ) );
+ global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >() );
global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate() );
global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate() );
+ global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate() );
}
- void installDBTypes( Handle<v8::Object>& global ){
- v8::Local<v8::FunctionTemplate> db = FunctionTemplate::New( dbInit );
+ void installDBTypes( Handle<v8::Object>& global ) {
+ v8::Local<v8::FunctionTemplate> db = newV8Function< dbInit >();
db->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
global->Set(v8::String::New("DB") , db->GetFunction() );
-
- v8::Local<v8::FunctionTemplate> dbCollection = FunctionTemplate::New( collectionInit );
+
+ v8::Local<v8::FunctionTemplate> dbCollection = newV8Function< collectionInit >();
dbCollection->InstanceTemplate()->SetNamedPropertyHandler( collectionFallback );
global->Set(v8::String::New("DBCollection") , dbCollection->GetFunction() );
- v8::Local<v8::FunctionTemplate> dbQuery = FunctionTemplate::New( dbQueryInit );
+ v8::Local<v8::FunctionTemplate> dbQuery = newV8Function< dbQueryInit >();
dbQuery->InstanceTemplate()->SetIndexedPropertyHandler( dbQueryIndexAccess );
global->Set(v8::String::New("DBQuery") , dbQuery->GetFunction() );
- global->Set( v8::String::New("ObjectId") , FunctionTemplate::New( objectIdInit )->GetFunction() );
+ global->Set( v8::String::New("ObjectId") , newV8Function< objectIdInit >()->GetFunction() );
- global->Set( v8::String::New("DBRef") , FunctionTemplate::New( dbRefInit )->GetFunction() );
-
- global->Set( v8::String::New("DBPointer") , FunctionTemplate::New( dbPointerInit )->GetFunction() );
+ global->Set( v8::String::New("DBRef") , newV8Function< dbRefInit >()->GetFunction() );
+
+ global->Set( v8::String::New("DBPointer") , newV8Function< dbPointerInit >()->GetFunction() );
global->Set( v8::String::New("BinData") , getBinDataFunctionTemplate()->GetFunction() );
global->Set( v8::String::New("NumberLong") , getNumberLongFunctionTemplate()->GetFunction() );
+ global->Set( v8::String::New("Timestamp") , getTimestampFunctionTemplate()->GetFunction() );
+
BSONObjBuilder b;
b.appendMaxKey( "" );
b.appendMinKey( "" );
@@ -131,21 +151,21 @@ namespace mongo {
BSONObjIterator i( o );
global->Set( v8::String::New("MaxKey"), mongoToV8Element( i.next() ) );
global->Set( v8::String::New("MinKey"), mongoToV8Element( i.next() ) );
-
- global->Get( v8::String::New( "Object" ) )->ToObject()->Set( v8::String::New("bsonsize") , FunctionTemplate::New( bsonsize )->GetFunction() );
+
+ global->Get( v8::String::New( "Object" ) )->ToObject()->Set( v8::String::New("bsonsize") , newV8Function< bsonsize >()->GetFunction() );
}
- void destroyConnection( Persistent<Value> self, void* parameter){
+ void destroyConnection( Persistent<Value> self, void* parameter) {
delete static_cast<DBClientBase*>(parameter);
self.Dispose();
self.Clear();
}
- Handle<Value> mongoConsExternal(const Arguments& args){
+ Handle<Value> mongoConsExternal(const Arguments& args) {
char host[255];
-
- if ( args.Length() > 0 && args[0]->IsString() ){
+
+ if ( args.Length() > 0 && args[0]->IsString() ) {
assert( args[0]->ToString()->Utf8Length() < 250 );
args[0]->ToString()->WriteAscii( host );
}
@@ -157,30 +177,41 @@ namespace mongo {
ConnectionString cs = ConnectionString::parse( host , errmsg );
if ( ! cs.isValid() )
return v8::ThrowException( v8::String::New( errmsg.c_str() ) );
-
-
- DBClientWithCommands * conn = cs.connect( errmsg );
+
+
+ DBClientWithCommands * conn;
+ {
+ V8Unlock ul;
+ conn = cs.connect( errmsg );
+ }
if ( ! conn )
return v8::ThrowException( v8::String::New( errmsg.c_str() ) );
-
+
Persistent<v8::Object> self = Persistent<v8::Object>::New( args.Holder() );
self.MakeWeak( conn , destroyConnection );
- ScriptEngine::runConnectCallback( *conn );
+ {
+ V8Unlock ul;
+ ScriptEngine::runConnectCallback( *conn );
+ }
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 ) );
-
+
return v8::Undefined();
}
- Handle<Value> mongoConsLocal(const Arguments& args){
-
+ Handle<Value> mongoConsLocal(const Arguments& args) {
+
if ( args.Length() > 0 )
return v8::ThrowException( v8::String::New( "local Mongo constructor takes no args" ) );
- DBClientBase * conn = createDirectClient();
+ DBClientBase * conn;
+ {
+ V8Unlock ul;
+ conn = createDirectClient();
+ }
Persistent<v8::Object> self = Persistent<v8::Object>::New( args.This() );
self.MakeWeak( conn , destroyConnection );
@@ -189,7 +220,7 @@ 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( "EMBEDDED" ) );
-
+
return v8::Undefined();
}
@@ -197,12 +228,12 @@ namespace mongo {
// ---
#ifdef _WIN32
-#define GETNS char * ns = new char[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns );
+#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 );
+#define GETNS char ns[args[0]->ToString()->Utf8Length()]; args[0]->ToString()->WriteUtf8( ns );
#endif
- DBClientBase * getConnection( const Arguments& args ){
+ DBClientBase * getConnection( const Arguments& args ) {
Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 )) );
DBClientBase * conn = (DBClientBase*)(c->Value());
assert( conn );
@@ -211,7 +242,7 @@ namespace mongo {
// ---- real methods
- void destroyCursor( Persistent<Value> self, void* parameter){
+ void destroyCursor( Persistent<Value> self, void* parameter) {
delete static_cast<mongo::DBClientCursor*>(parameter);
self.Dispose();
self.Clear();
@@ -224,60 +255,64 @@ namespace mongo {
3 - limit
4 - skip
*/
- Handle<Value> mongoFind(const Arguments& args){
+ Handle<Value> mongoFind(const Arguments& args) {
HandleScope handle_scope;
- jsassert( args.Length() == 6 , "find needs 6 args" );
+ jsassert( args.Length() == 7 , "find needs 7 args" );
jsassert( args[1]->IsObject() , "needs to be an object" );
DBClientBase * 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());
int batchSize = (int)(args[5]->ToNumber()->Value());
+ int options = (int)(args[6]->ToNumber()->Value());
{
- v8::Unlocker u;
- cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, slaveOk ? QueryOption_SlaveOk : 0 , batchSize );
+ V8Unlock u;
+ cursor = conn->query( ns, q , nToReturn , nToSkip , haveFields ? &fields : 0, options | ( slaveOk ? QueryOption_SlaveOk : 0 ) , batchSize );
}
v8::Function * cons = (v8::Function*)( *( mongo->Get( v8::String::New( "internalCursor" ) ) ) );
assert( cons );
-
+
Persistent<v8::Object> c = Persistent<v8::Object>::New( cons->NewInstance() );
c.MakeWeak( cursor.get() , destroyCursor );
-
+
c->SetInternalField( 0 , External::New( cursor.release() ) );
return handle_scope.Close(c);
}
- catch ( ... ){
- return v8::ThrowException( v8::String::New( "socket error on query" ) );
+ catch ( ... ) {
+ return v8::ThrowException( v8::String::New( "socket error on query" ) );
}
}
- v8::Handle<v8::Value> mongoInsert(const v8::Arguments& args){
+ 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" );
-
+
+ if ( args.This()->Get( v8::String::New( "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();
-
- if ( ! in->Has( v8::String::New( "_id" ) ) ){
+
+ if ( ! in->Has( v8::String::New( "_id" ) ) ) {
v8::Handle<v8::Value> argv[1];
in->Set( v8::String::New( "_id" ) , getObjectIdCons()->NewInstance( 0 , argv ) );
}
@@ -286,64 +321,70 @@ namespace mongo {
DDD( "want to save : " << o.jsonString() );
try {
- v8::Unlocker u;
+ V8Unlock u;
conn->insert( ns , o );
}
- catch ( ... ){
+ catch ( ... ) {
return v8::ThrowException( v8::String::New( "socket error on insert" ) );
}
-
+
return v8::Undefined();
}
- v8::Handle<v8::Value> mongoRemove(const v8::Arguments& args){
+ v8::Handle<v8::Value> mongoRemove(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() )
+ 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 );
-
+
bool justOne = false;
- if ( args.Length() > 2 ){
+ if ( args.Length() > 2 ) {
justOne = args[2]->BooleanValue();
}
DDD( "want to remove : " << o.jsonString() );
try {
- v8::Unlocker u;
+ V8Unlock u;
conn->remove( ns , o , justOne );
}
- catch ( ... ){
+ catch ( ... ) {
return v8::ThrowException( v8::String::New( "socket error on remove" ) );
}
return v8::Undefined();
}
- v8::Handle<v8::Value> mongoUpdate(const v8::Arguments& args){
+ 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" );
+
+ if ( args.This()->Get( v8::String::New( "readOnly" ) )->BooleanValue() )
+ return v8::ThrowException( v8::String::New( "js db in read only mode" ) );
DBClientBase * 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();
- bool multi = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value();
-
+ bool multi = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value();
+
try {
BSONObj q1 = v8ToMongo( q );
BSONObj o1 = v8ToMongo( o );
- v8::Unlocker u;
+ V8Unlock u;
conn->update( ns , q1 , o1 , upsert, multi );
}
- catch ( ... ){
+ catch ( ... ) {
return v8::ThrowException( v8::String::New( "socket error on remove" ) );
}
@@ -355,48 +396,48 @@ namespace mongo {
// --- cursor ---
- mongo::DBClientCursor * getCursor( const Arguments& args ){
+ mongo::DBClientCursor * getCursor( const Arguments& args ) {
Local<External> c = External::Cast( *(args.This()->GetInternalField( 0 ) ) );
mongo::DBClientCursor * cursor = (mongo::DBClientCursor*)(c->Value());
return cursor;
}
- v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args){
+ v8::Handle<v8::Value> internalCursorCons(const v8::Arguments& args) {
return v8::Undefined();
}
- v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args){
+ v8::Handle<v8::Value> internalCursorNext(const v8::Arguments& args) {
mongo::DBClientCursor * cursor = getCursor( args );
if ( ! cursor )
return v8::Undefined();
BSONObj o;
{
- v8::Unlocker u;
+ V8Unlock u;
o = cursor->next();
}
return mongoToV8( o );
}
- v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args){
+ v8::Handle<v8::Value> internalCursorHasNext(const v8::Arguments& args) {
mongo::DBClientCursor * cursor = getCursor( args );
if ( ! cursor )
return Boolean::New( false );
bool ret;
{
- v8::Unlocker u;
+ V8Unlock u;
ret = cursor->more();
}
return Boolean::New( ret );
}
- v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args){
+ v8::Handle<v8::Value> internalCursorObjsLeftInBatch(const v8::Arguments& args) {
mongo::DBClientCursor * cursor = getCursor( args );
if ( ! cursor )
return v8::Number::New( (double) 0 );
int ret;
{
- v8::Unlocker u;
+ V8Unlock u;
ret = cursor->objsLeftInBatch();
}
return v8::Number::New( (double) ret );
@@ -405,7 +446,7 @@ namespace mongo {
// --- DB ----
- v8::Handle<v8::Value> dbInit(const v8::Arguments& args){
+ v8::Handle<v8::Value> dbInit(const v8::Arguments& args) {
assert( args.Length() == 2 );
args.This()->Set( v8::String::New( "_mongo" ) , args[0] );
@@ -417,26 +458,29 @@ namespace mongo {
return v8::Undefined();
}
- v8::Handle<v8::Value> collectionInit( const v8::Arguments& args ){
+ 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] );
-
+
+ if ( haveLocalShardingInfo( toSTLString( args[3] ) ) )
+ return v8::ThrowException( v8::String::New( "can't use sharded collection from db.eval" ) );
+
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::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] );
@@ -444,46 +488,52 @@ namespace mongo {
if ( args.Length() > 4 && args[4]->IsObject() )
t->Set( v8::String::New( "_query" ) , args[4] );
- else
+ 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
+ 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
+ else
t->Set( v8::String::New( "_skip" ) , Number::New( 0 ) );
if ( args.Length() > 8 && args[8]->IsNumber() )
- t->Set( v8::String::New( "_batchSize" ) , args[7] );
- else
+ t->Set( v8::String::New( "_batchSize" ) , args[8] );
+ else
t->Set( v8::String::New( "_batchSize" ) , Number::New( 0 ) );
-
+
+ if ( args.Length() > 9 && args[9]->IsNumber() )
+ t->Set( v8::String::New( "_options" ) , args[9] );
+ else
+ t->Set( v8::String::New( "_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) );
-
+
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 ( sname[0] == '_' ) {
if ( ! ( info.This()->HasRealNamedProperty( name ) ) )
return v8::Undefined();
return info.This()->GetRealNamedPropertyInPrototypeChain( name );
@@ -499,7 +549,7 @@ namespace mongo {
return f->Call( info.This() , 1 , argv );
}
- v8::Handle<v8::Value> dbQueryIndexAccess( unsigned int index , const v8::AccessorInfo& info ){
+ 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() );
@@ -507,35 +557,36 @@ namespace mongo {
v8::Handle<v8::Value> argv[1];
argv[0] = v8::Number::New( index );
- return f->Call( info.This() , 1 , argv );
+ return f->Call( info.This() , 1 , argv );
}
- v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ){
+ v8::Handle<v8::Value> objectIdInit( const v8::Arguments& args ) {
v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function * f = getObjectIdCons();
it = f->NewInstance();
}
-
+
OID oid;
-
- if ( args.Length() == 0 ){
+
+ if ( args.Length() == 0 ) {
oid.init();
}
else {
string s = toSTLString( args[0] );
try {
Scope::validateObjectIdString( s );
- } catch ( const MsgAssertionException &m ) {
+ }
+ catch ( const MsgAssertionException &m ) {
string error = m.toString();
return v8::ThrowException( v8::String::New( error.c_str() ) );
- }
+ }
oid.init( s );
- }
+ }
it->Set( v8::String::New( "str" ) , v8::String::New( oid.str().c_str() ) );
-
+
return it;
}
@@ -547,7 +598,7 @@ namespace mongo {
v8::Handle<v8::Object> it = args.This();
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function* f = getNamedCons( "DBRef" );
it = f->NewInstance();
}
@@ -561,74 +612,98 @@ namespace mongo {
}
v8::Handle<v8::Value> dbPointerInit( const v8::Arguments& args ) {
-
+
if (args.Length() != 2) {
return v8::ThrowException( v8::String::New( "DBPointer needs 2 arguments" ) );
}
-
+
v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function* f = 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 ) );
-
+
+ return it;
+ }
+
+ v8::Handle<v8::Value> dbTimestampInit( 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 ) );
+ }
+ else if ( args.Length() == 2 ) {
+ it->Set( v8::String::New( "t" ) , args[0] );
+ it->Set( v8::String::New( "i" ) , args[1] );
+ }
+ else {
+ return v8::ThrowException( v8::String::New( "Timestamp needs 0 or 2 arguments" ) );
+ }
+
+ it->SetInternalField( 0, v8::Uint32::New( Timestamp ) );
+
return it;
}
+
v8::Handle<v8::Value> binDataInit( const v8::Arguments& args ) {
v8::Handle<v8::Object> it = args.This();
-
+
// 3 args: len, type, data
if (args.Length() == 3) {
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function* f = 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
- } else if ( args.Length() == 2 ) {
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+ // 2 args: type, base64 string
+ }
+ else if ( args.Length() == 2 ) {
+
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function* f = 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 ) );
-
- } else {
+ it->SetHiddenValue( v8::String::New( "__BinData" ), v8::Number::New( 1 ) );
+
+ }
+ else {
return v8::ThrowException( v8::String::New( "BinData needs 3 arguments" ) );
}
return it;
}
-
+
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::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" ) ) );
-
+
stringstream ss;
ss << "BinData(" << type << ",\"";
base64::encode( ss, *data, len );
@@ -638,49 +713,54 @@ namespace mongo {
}
v8::Handle<v8::Value> numberLongInit( 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" ) );
}
-
+
v8::Handle<v8::Object> it = args.This();
-
- if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ){
+
+ if ( it->IsUndefined() || it == v8::Context::GetCurrent()->Global() ) {
v8::Function* f = getNamedCons( "NumberLong" );
it = f->NewInstance();
}
if ( args.Length() == 0 ) {
it->Set( v8::String::New( "floatApprox" ), v8::Number::New( 0 ) );
- } else if ( args.Length() == 1 ) {
+ }
+ else if ( args.Length() == 1 ) {
if ( args[ 0 ]->IsNumber() ) {
- it->Set( v8::String::New( "floatApprox" ), args[ 0 ] );
- } else {
+ it->Set( v8::String::New( "floatApprox" ), args[ 0 ] );
+ }
+ else {
v8::String::Utf8Value data( args[ 0 ] );
string num = *data;
const char *numStr = num.c_str();
long long n;
try {
n = parseLL( numStr );
- } catch ( const AssertionException & ) {
+ }
+ catch ( const AssertionException & ) {
return v8::ThrowException( v8::String::New( "could not convert string to long long" ) );
}
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 ) ) );
- } else {
+ }
+ 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) ) );
- }
+ }
}
- } else {
+ }
+ 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->SetHiddenValue( v8::String::New( "__NumberLong" ), v8::Number::New( 1 ) );
-
+
return it;
}
@@ -688,21 +768,21 @@ namespace mongo {
if ( !it->Has( v8::String::New( "top" ) ) )
return (long long)( it->Get( v8::String::New( "floatApprox" ) )->NumberValue() );
return
- (long long)
- ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
- (unsigned)( it->Get( v8::String::New( "bottom" ) )->ToInt32()->Value() );
+ (long long)
+ ( (unsigned long long)( it->Get( v8::String::New( "top" ) )->ToInt32()->Value() ) << 32 ) +
+ (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::Object> it = args.This();
-
+
long long val = numberLongVal( it );
-
+
return v8::Number::New( double( val ) );
}
@@ -711,13 +791,13 @@ namespace mongo {
}
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::Object> it = args.This();
-
+
stringstream ss;
long long val = numberLongVal( it );
const long long limit = 2LL << 30;
@@ -730,13 +810,65 @@ namespace mongo {
string ret = ss.str();
return v8::String::New( ret.c_str() );
}
-
+
v8::Handle<v8::Value> bsonsize( const v8::Arguments& args ) {
-
- if (args.Length() != 1 || !args[ 0 ]->IsObject()) {
- return v8::ThrowException( v8::String::New( "bonsisze needs 1 object" ) );
- }
+
+ if ( args.Length() != 1 )
+ return v8::ThrowException( v8::String::New( "bonsisze 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::Number::New( v8ToMongo( args[ 0 ]->ToObject() ).objsize() );
}
+
+ // to be called with v8 mutex
+ void enableV8Interrupt() {
+ if ( globalScriptEngine->haveGetInterruptSpecCallback() ) {
+ __interruptSpecToThreadId[ globalScriptEngine->getInterruptSpec() ] = v8::V8::GetCurrentThreadId();
+ }
+ }
+
+ // to be called with v8 mutex
+ void disableV8Interrupt() {
+ if ( globalScriptEngine->haveGetInterruptSpecCallback() ) {
+ __interruptSpecToThreadId.erase( globalScriptEngine->getInterruptSpec() );
+ }
+ }
+
+ namespace v8Locks {
+ boost::mutex& __v8Mutex = *( new boost::mutex );
+ ThreadLocalValue< bool > __locked;
+
+ RecursiveLock::RecursiveLock() : _unlock() {
+ if ( !__locked.get() ) {
+ __v8Mutex.lock();
+ __locked.set( true );
+ _unlock = true;
+ }
+ }
+ RecursiveLock::~RecursiveLock() {
+ if ( _unlock ) {
+ __v8Mutex.unlock();
+ __locked.set( false );
+ }
+ }
+
+ RecursiveUnlock::RecursiveUnlock() : _lock() {
+ if ( __locked.get() ) {
+ __v8Mutex.unlock();
+ __locked.set( false );
+ _lock = true;
+ }
+ }
+ RecursiveUnlock::~RecursiveUnlock() {
+ if ( _lock ) {
+ __v8Mutex.lock();
+ __locked.set( true );
+ }
+ }
+ } // namespace v8Locks
}