diff options
Diffstat (limited to 'src/mongo/scripting/v8-3.25_db.cpp')
-rw-r--r-- | src/mongo/scripting/v8-3.25_db.cpp | 1719 |
1 files changed, 834 insertions, 885 deletions
diff --git a/src/mongo/scripting/v8-3.25_db.cpp b/src/mongo/scripting/v8-3.25_db.cpp index 147dcbbf563..e4fd6d890c2 100644 --- a/src/mongo/scripting/v8-3.25_db.cpp +++ b/src/mongo/scripting/v8-3.25_db.cpp @@ -49,1082 +49,1031 @@ using std::shared_ptr; namespace mongo { - namespace { - std::vector<V8FunctionPrototypeManipulatorFn> _mongoPrototypeManipulators; - bool _mongoPrototypeManipulatorsFrozen = false; +namespace { +std::vector<V8FunctionPrototypeManipulatorFn> _mongoPrototypeManipulators; +bool _mongoPrototypeManipulatorsFrozen = false; - MONGO_INITIALIZER(V8MongoPrototypeManipulatorRegistry)(InitializerContext* context) { - return Status::OK(); - } - - MONGO_INITIALIZER_WITH_PREREQUISITES(V8MongoPrototypeManipulatorRegistrationDone, - ("V8MongoPrototypeManipulatorRegistry")) - (InitializerContext* context) { +MONGO_INITIALIZER(V8MongoPrototypeManipulatorRegistry)(InitializerContext* context) { + return Status::OK(); +} - _mongoPrototypeManipulatorsFrozen = true; - return Status::OK(); - } +MONGO_INITIALIZER_WITH_PREREQUISITES(V8MongoPrototypeManipulatorRegistrationDone, + ("V8MongoPrototypeManipulatorRegistry")) +(InitializerContext* context) { + _mongoPrototypeManipulatorsFrozen = true; + return Status::OK(); +} - } // namespace +} // namespace - void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManipulatorFn& manipulator) { - fassert(16467, !_mongoPrototypeManipulatorsFrozen); - _mongoPrototypeManipulators.push_back(manipulator); - } +void v8RegisterMongoPrototypeManipulator(const V8FunctionPrototypeManipulatorFn& manipulator) { + fassert(16467, !_mongoPrototypeManipulatorsFrozen); + _mongoPrototypeManipulators.push_back(manipulator); +} - static v8::Local<v8::Value> newInstance(v8::Local<v8::Function> f, - const v8::FunctionCallbackInfo<v8::Value>& args) { - // need to translate arguments into an array - v8::EscapableHandleScope handle_scope(args.GetIsolate()); - const int argc = args.Length(); - static const int MAX_ARGC = 24; - uassert(16858, "Too many arguments. Max is 24", - argc <= MAX_ARGC); - - // TODO SERVER-8016: properly allocate handles on the stack - v8::Local<v8::Value> argv[MAX_ARGC]; - for (int i = 0; i < argc; ++i) { - argv[i] = args[i]; - } - return handle_scope.Escape(f->NewInstance(argc, argv)); +static v8::Local<v8::Value> newInstance(v8::Local<v8::Function> f, + const v8::FunctionCallbackInfo<v8::Value>& args) { + // need to translate arguments into an array + v8::EscapableHandleScope handle_scope(args.GetIsolate()); + const int argc = args.Length(); + static const int MAX_ARGC = 24; + uassert(16858, "Too many arguments. Max is 24", argc <= MAX_ARGC); + + // TODO SERVER-8016: properly allocate handles on the stack + v8::Local<v8::Value> argv[MAX_ARGC]; + for (int i = 0; i < argc; ++i) { + argv[i] = args[i]; } + return handle_scope.Escape(f->NewInstance(argc, argv)); +} - v8::Local<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope) { - v8::Local<v8::FunctionTemplate> ic = scope->createV8Function(internalCursorCons); - ic->InstanceTemplate()->SetInternalFieldCount(1); - v8::Local<v8::ObjectTemplate> icproto = ic->PrototypeTemplate(); - scope->injectV8Method("next", internalCursorNext, icproto); - scope->injectV8Method("hasNext", internalCursorHasNext, icproto); - scope->injectV8Method("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto); - scope->injectV8Method("readOnly", internalCursorReadOnly, icproto); - return ic; - } +v8::Local<v8::FunctionTemplate> getInternalCursorFunctionTemplate(V8Scope* scope) { + v8::Local<v8::FunctionTemplate> ic = scope->createV8Function(internalCursorCons); + ic->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::ObjectTemplate> icproto = ic->PrototypeTemplate(); + scope->injectV8Method("next", internalCursorNext, icproto); + scope->injectV8Method("hasNext", internalCursorHasNext, icproto); + scope->injectV8Method("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto); + scope->injectV8Method("readOnly", internalCursorReadOnly, icproto); + return ic; +} - v8::Local<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scope, bool local) { - v8::Local<v8::FunctionTemplate> mongo; - if (local) - mongo = scope->createV8Function(mongoConsLocal); - else - mongo = scope->createV8Function(mongoConsExternal); - mongo->InstanceTemplate()->SetInternalFieldCount(1); - v8::Local<v8::ObjectTemplate> proto = mongo->PrototypeTemplate(); - scope->injectV8Method("find", mongoFind, proto); - scope->injectV8Method("insert", mongoInsert, proto); - scope->injectV8Method("remove", mongoRemove, proto); - scope->injectV8Method("update", mongoUpdate, proto); - scope->injectV8Method("auth", mongoAuth, proto); - scope->injectV8Method("logout", mongoLogout, proto); - scope->injectV8Method("cursorFromId", mongoCursorFromId, proto); - - fassert(16468, _mongoPrototypeManipulatorsFrozen); - for (size_t i = 0; i < _mongoPrototypeManipulators.size(); ++i) - _mongoPrototypeManipulators[i](scope, mongo); - - return mongo; - } +v8::Local<v8::FunctionTemplate> getMongoFunctionTemplate(V8Scope* scope, bool local) { + v8::Local<v8::FunctionTemplate> mongo; + if (local) + mongo = scope->createV8Function(mongoConsLocal); + else + mongo = scope->createV8Function(mongoConsExternal); + mongo->InstanceTemplate()->SetInternalFieldCount(1); + v8::Local<v8::ObjectTemplate> proto = mongo->PrototypeTemplate(); + scope->injectV8Method("find", mongoFind, proto); + scope->injectV8Method("insert", mongoInsert, proto); + scope->injectV8Method("remove", mongoRemove, proto); + scope->injectV8Method("update", mongoUpdate, proto); + scope->injectV8Method("auth", mongoAuth, proto); + scope->injectV8Method("logout", mongoLogout, proto); + scope->injectV8Method("cursorFromId", mongoCursorFromId, proto); + + fassert(16468, _mongoPrototypeManipulatorsFrozen); + for (size_t i = 0; i < _mongoPrototypeManipulators.size(); ++i) + _mongoPrototypeManipulators[i](scope, mongo); + + return mongo; +} - v8::Local<v8::Value> mongoConsExternal(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - string host = "127.0.0.1"; - if (args.Length() > 0 && args[0]->IsString()) { - v8::String::Utf8Value utf(args[0]); - host = string(*utf); - } +v8::Local<v8::Value> mongoConsExternal(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + string host = "127.0.0.1"; + if (args.Length() > 0 && args[0]->IsString()) { + v8::String::Utf8Value utf(args[0]); + host = string(*utf); + } - // only allow function template to be used by a constructor - uassert(16859, "Mongo function is only usable as a constructor", - args.IsConstructCall()); - verify(scope->MongoFT()->HasInstance(args.This())); + // only allow function template to be used by a constructor + uassert(16859, "Mongo function is only usable as a constructor", args.IsConstructCall()); + verify(scope->MongoFT()->HasInstance(args.This())); - auto statusWithHost = ConnectionString::parse(host); - if (!status.isOK()) { - return v8AssertionException(statusWithHost.getStatus().reason()); - } + auto statusWithHost = ConnectionString::parse(host); + if (!status.isOK()) { + return v8AssertionException(statusWithHost.getStatus().reason()); + } - const ConnectionString cs(statusWithHost.getValue()); + const ConnectionString cs(statusWithHost.getValue()); - string errmsg; - DBClientBase* conn; - conn = cs.connect(errmsg); - if (!conn) { - return v8AssertionException(errmsg); - } + string errmsg; + DBClientBase* conn; + conn = cs.connect(errmsg); + if (!conn) { + return v8AssertionException(errmsg); + } - v8::Local<v8::External> connHandle = - scope->dbClientBaseTracker.track(scope->getIsolate(), args.This(), conn); + v8::Local<v8::External> connHandle = + scope->dbClientBaseTracker.track(scope->getIsolate(), args.This(), conn); - ScriptEngine::runConnectCallback(*conn); + ScriptEngine::runConnectCallback(*conn); - args.This()->SetInternalField(0, connHandle); - args.This()->ForceSet(scope->v8StringData("slaveOk"), - v8::Boolean::New(scope->getIsolate(), false)); - args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData(host)); + args.This()->SetInternalField(0, connHandle); + args.This()->ForceSet(scope->v8StringData("slaveOk"), + v8::Boolean::New(scope->getIsolate(), false)); + args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData(host)); - return v8::Undefined(scope->getIsolate()); - } + return v8::Undefined(scope->getIsolate()); +} - v8::Local<v8::Value> mongoConsLocal(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 0, "local Mongo constructor takes no args") +v8::Local<v8::Value> mongoConsLocal(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 0, "local Mongo constructor takes no args") // only allow function template to be used by a constructor - uassert(16860, "Mongo function is only usable as a constructor", - args.IsConstructCall()); - verify(scope->MongoFT()->HasInstance(args.This())); + uassert(16860, "Mongo function is only usable as a constructor", args.IsConstructCall()); + verify(scope->MongoFT()->HasInstance(args.This())); - DBClientBase* conn = createDirectClient(scope->getOpContext()); - v8::Local<v8::External> connHandle = - scope->dbClientBaseTracker.track(scope->getIsolate(), args.This(), conn); + DBClientBase* conn = createDirectClient(scope->getOpContext()); + v8::Local<v8::External> connHandle = + scope->dbClientBaseTracker.track(scope->getIsolate(), args.This(), conn); - args.This()->SetInternalField(0, connHandle); - args.This()->ForceSet(scope->v8StringData("slaveOk"), - v8::Boolean::New(scope->getIsolate(), false)); - args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData("EMBEDDED")); + args.This()->SetInternalField(0, connHandle); + args.This()->ForceSet(scope->v8StringData("slaveOk"), + v8::Boolean::New(scope->getIsolate(), false)); + args.This()->ForceSet(scope->v8StringData("host"), scope->v8StringData("EMBEDDED")); - return v8::Undefined(scope->getIsolate()); - } + return v8::Undefined(scope->getIsolate()); +} - std::shared_ptr<mongo::DBClientBase> getConnection(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - verify(scope->MongoFT()->HasInstance(args.This())); - verify(args.This()->InternalFieldCount() == 1); - v8::Local<v8::External> c = - v8::Local<v8::External>::Cast(args.This()->GetInternalField(0)); - std::shared_ptr<DBClientBase>* conn = - static_cast<std::shared_ptr<DBClientBase>*>(c->Value()); - massert(16667, "Unable to get db client connection", conn && conn->get()); - return *conn; - } - - /** - * JavaScript binding for Mongo.prototype.find(namespace, query, fields, limit, skip) - */ - v8::Local<v8::Value> mongoFind(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 7, "find needs 7 args") - argumentCheck(args[1]->IsObject(), "needs to be an object") - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string ns = toSTLString(args[0]); - BSONObj fields; - BSONObj q = scope->v8ToMongo(args[1]->ToObject()); - bool haveFields = args[2]->IsObject() && - args[2]->ToObject()->GetPropertyNames()->Length() > 0; - if (haveFields) - fields = scope->v8ToMongo(args[2]->ToObject()); - - std::shared_ptr<mongo::DBClientCursor> cursor; - int nToReturn = args[3]->Int32Value(); - int nToSkip = args[4]->Int32Value(); - int batchSize = args[5]->Int32Value(); - int options = args[6]->Int32Value(); - cursor = conn->query(ns, q, nToReturn, nToSkip, haveFields ? &fields : NULL, - options, batchSize); - if (!cursor.get()) { - return v8AssertionException("error doing query: failed"); - } +std::shared_ptr<mongo::DBClientBase> getConnection( + V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + verify(scope->MongoFT()->HasInstance(args.This())); + verify(args.This()->InternalFieldCount() == 1); + v8::Local<v8::External> c = v8::Local<v8::External>::Cast(args.This()->GetInternalField(0)); + std::shared_ptr<DBClientBase>* conn = static_cast<std::shared_ptr<DBClientBase>*>(c->Value()); + massert(16667, "Unable to get db client connection", conn && conn->get()); + return *conn; +} - v8::Local<v8::Function> cons = scope->InternalCursorFT()->GetFunction(); - v8::Local<v8::Object> c = cons->NewInstance(); - c->SetInternalField(0, v8::External::New(scope->getIsolate(), cursor.get())); - scope->dbConnectionAndCursor.track(scope->getIsolate(), c, - new V8Scope::DBConnectionAndCursor(conn, cursor)); - return c; +/** + * JavaScript binding for Mongo.prototype.find(namespace, query, fields, limit, skip) + */ +v8::Local<v8::Value> mongoFind(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 7, "find needs 7 args") + argumentCheck(args[1]->IsObject(), "needs to be an object") + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + const string ns = toSTLString(args[0]); + BSONObj fields; + BSONObj q = scope->v8ToMongo(args[1]->ToObject()); + bool haveFields = args[2]->IsObject() && args[2]->ToObject()->GetPropertyNames()->Length() > 0; + if (haveFields) + fields = scope->v8ToMongo(args[2]->ToObject()); + + std::shared_ptr<mongo::DBClientCursor> cursor; + int nToReturn = args[3]->Int32Value(); + int nToSkip = args[4]->Int32Value(); + int batchSize = args[5]->Int32Value(); + int options = args[6]->Int32Value(); + cursor = + conn->query(ns, q, nToReturn, nToSkip, haveFields ? &fields : NULL, options, batchSize); + if (!cursor.get()) { + return v8AssertionException("error doing query: failed"); } - v8::Local<v8::Value> mongoCursorFromId(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 2 || args.Length() == 3, "cursorFromId needs 2 or 3 args") + v8::Local<v8::Function> cons = scope->InternalCursorFT()->GetFunction(); + v8::Local<v8::Object> c = cons->NewInstance(); + c->SetInternalField(0, v8::External::New(scope->getIsolate(), cursor.get())); + scope->dbConnectionAndCursor.track( + scope->getIsolate(), c, new V8Scope::DBConnectionAndCursor(conn, cursor)); + return c; +} + +v8::Local<v8::Value> mongoCursorFromId(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 2 || args.Length() == 3, "cursorFromId needs 2 or 3 args") argumentCheck(scope->NumberLongFT()->HasInstance(args[1]), "2nd arg must be a NumberLong") - argumentCheck(args[2]->IsUndefined() || args[2]->IsNumber(), "3rd arg must be a js Number") + argumentCheck(args[2]->IsUndefined() || args[2]->IsNumber(), + "3rd arg must be a js Number") - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string ns = toSTLString(args[0]); - long long cursorId = numberLongVal(scope, args[1]->ToObject()); + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + const string ns = toSTLString(args[0]); + long long cursorId = numberLongVal(scope, args[1]->ToObject()); - std::shared_ptr<mongo::DBClientCursor> cursor( - new DBClientCursor(conn.get(), ns, cursorId, 0, 0)); + std::shared_ptr<mongo::DBClientCursor> cursor( + new DBClientCursor(conn.get(), ns, cursorId, 0, 0)); - if (!args[2]->IsUndefined()) - cursor->setBatchSize(args[2]->Int32Value()); + if (!args[2]->IsUndefined()) + cursor->setBatchSize(args[2]->Int32Value()); - v8::Local<v8::Function> cons = scope->InternalCursorFT()->GetFunction(); - v8::Local<v8::Object> c = cons->NewInstance(); - c->SetInternalField(0, v8::External::New(scope->getIsolate(), cursor.get())); - scope->dbConnectionAndCursor.track(scope->getIsolate(), c, - new V8Scope::DBConnectionAndCursor(conn, cursor)); - return c; - } + v8::Local<v8::Function> cons = scope->InternalCursorFT()->GetFunction(); + v8::Local<v8::Object> c = cons->NewInstance(); + c->SetInternalField(0, v8::External::New(scope->getIsolate(), cursor.get())); + scope->dbConnectionAndCursor.track( + scope->getIsolate(), c, new V8Scope::DBConnectionAndCursor(conn, cursor)); + return c; +} - v8::Local<v8::Value> mongoInsert(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 3 ,"insert needs 3 args") - argumentCheck(args[1]->IsObject() ,"attempted to insert a non-object") +v8::Local<v8::Value> mongoInsert(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 3, "insert needs 3 args") + argumentCheck(args[1]->IsObject(), "attempted to insert a non-object") - verify(scope->MongoFT()->HasInstance(args.This())); + verify(scope->MongoFT()->HasInstance(args.This())); - if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { - return v8AssertionException("js db in read only mode"); - } + if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { + return v8AssertionException("js db in read only mode"); + } - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string ns = toSTLString(args[0]); + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + const string ns = toSTLString(args[0]); - v8::Local<v8::Integer> flags = args[2]->ToInteger(); + v8::Local<v8::Integer> flags = args[2]->ToInteger(); - if(args[1]->IsArray()){ - v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(args[1]); - vector<BSONObj> bos; - uint32_t len = arr->Length(); - argumentCheck(len > 0, "attempted to insert an empty array") + if (args[1]->IsArray()) { + v8::Local<v8::Array> arr = v8::Local<v8::Array>::Cast(args[1]); + vector<BSONObj> bos; + uint32_t len = arr->Length(); + argumentCheck(len > 0, "attempted to insert an empty array") - for(uint32_t i = 0; i < len; i++){ - v8::Local<v8::Object> el = arr->CloneElementAt(i); - argumentCheck(!el.IsEmpty(), "attempted to insert an array of non-object types") + for (uint32_t i = 0; i < len; i++) { + v8::Local<v8::Object> el = arr->CloneElementAt(i); + argumentCheck(!el.IsEmpty(), "attempted to insert an array of non-object types") // Set ID on the element if necessary if (!el->Has(scope->v8StringData("_id"))) { - v8::Local<v8::Value> argv[1]; - el->ForceSet(scope->v8StringData("_id"), - scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv)); - } - bos.push_back(scope->v8ToMongo(el)); - } - conn->insert(ns, bos, flags->Int32Value()); - } - else { - v8::Local<v8::Object> in = args[1]->ToObject(); - if (!in->Has(scope->v8StringData("_id"))) { v8::Local<v8::Value> argv[1]; - in->ForceSet(scope->v8StringData("_id"), + el->ForceSet(scope->v8StringData("_id"), scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv)); } - BSONObj o = scope->v8ToMongo(in); - conn->insert(ns, o); + bos.push_back(scope->v8ToMongo(el)); } - return v8::Undefined(scope->getIsolate()); + conn->insert(ns, bos, flags->Int32Value()); + } else { + v8::Local<v8::Object> in = args[1]->ToObject(); + if (!in->Has(scope->v8StringData("_id"))) { + v8::Local<v8::Value> argv[1]; + in->ForceSet(scope->v8StringData("_id"), + scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv)); + } + BSONObj o = scope->v8ToMongo(in); + conn->insert(ns, o); } + return v8::Undefined(scope->getIsolate()); +} - v8::Local<v8::Value> mongoRemove(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 2 || args.Length() == 3, "remove needs 2 or 3 args") +v8::Local<v8::Value> mongoRemove(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 2 || args.Length() == 3, "remove needs 2 or 3 args") argumentCheck(args[1]->IsObject(), "attempted to remove a non-object") - verify(scope->MongoFT()->HasInstance(args.This())); + verify(scope->MongoFT()->HasInstance(args.This())); - if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { - return v8AssertionException("js db in read only mode"); - } + if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { + return v8AssertionException("js db in read only mode"); + } - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string ns = toSTLString(args[0]); + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + const string ns = toSTLString(args[0]); - v8::Local<v8::Object> in = args[1]->ToObject(); - BSONObj o = scope->v8ToMongo(in); + v8::Local<v8::Object> in = args[1]->ToObject(); + BSONObj o = scope->v8ToMongo(in); - bool justOne = false; - if (args.Length() > 2) { - justOne = args[2]->BooleanValue(); - } - - conn->remove(ns, o, justOne); - return v8::Undefined(scope->getIsolate()); + bool justOne = false; + if (args.Length() > 2) { + justOne = args[2]->BooleanValue(); } - v8::Local<v8::Value> mongoUpdate(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() >= 3, "update needs at least 3 args") + conn->remove(ns, o, justOne); + return v8::Undefined(scope->getIsolate()); +} + +v8::Local<v8::Value> mongoUpdate(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() >= 3, "update needs at least 3 args") argumentCheck(args[1]->IsObject(), "1st param to update has to be an object") - argumentCheck(args[2]->IsObject(), "2nd param to update has to be an object") + argumentCheck(args[2]->IsObject(), "2nd param to update has to be an object") - verify(scope->MongoFT()->HasInstance(args.This())); + verify(scope->MongoFT()->HasInstance(args.This())); - if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { - return v8AssertionException("js db in read only mode"); - } + if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { + return v8AssertionException("js db in read only mode"); + } - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string ns = toSTLString(args[0]); + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + const string ns = toSTLString(args[0]); - v8::Local<v8::Object> q = args[1]->ToObject(); - v8::Local<v8::Object> o = args[2]->ToObject(); + v8::Local<v8::Object> q = args[1]->ToObject(); + v8::Local<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 upsert = args.Length() > 3 && args[3]->IsBoolean() && args[3]->ToBoolean()->Value(); + bool multi = args.Length() > 4 && args[4]->IsBoolean() && args[4]->ToBoolean()->Value(); - BSONObj q1 = scope->v8ToMongo(q); - BSONObj o1 = scope->v8ToMongo(o); - conn->update(ns, q1, o1, upsert, multi); - return v8::Undefined(scope->getIsolate()); - } + BSONObj q1 = scope->v8ToMongo(q); + BSONObj o1 = scope->v8ToMongo(o); + conn->update(ns, q1, o1, upsert, multi); + return v8::Undefined(scope->getIsolate()); +} - v8::Local<v8::Value> mongoAuth(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - if (NULL == conn) - return v8AssertionException("no connection"); +v8::Local<v8::Value> mongoAuth(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + std::shared_ptr<DBClientBase> conn = getConnection(scope, args); + if (NULL == conn) + return v8AssertionException("no connection"); - BSONObj params; - switch (args.Length()) { + BSONObj params; + switch (args.Length()) { case 1: params = scope->v8ToMongo(args[0]->ToObject()); break; case 3: - params = BSON(saslCommandMechanismFieldName << "MONGODB-CR" << - saslCommandUserDBFieldName << toSTLString(args[0]) << - saslCommandUserFieldName << toSTLString(args[1]) << - saslCommandPasswordFieldName << toSTLString(args[2])); + params = BSON(saslCommandMechanismFieldName + << "MONGODB-CR" << saslCommandUserDBFieldName << toSTLString(args[0]) + << saslCommandUserFieldName << toSTLString(args[1]) + << saslCommandPasswordFieldName << toSTLString(args[2])); break; default: return v8AssertionException("mongoAuth takes 1 object or 3 string arguments"); - } - try { - conn->auth(params); - } - catch (const DBException& ex) { - return v8AssertionException(ex.toString()); - } - return v8::Boolean::New(scope->getIsolate(), true); } - - v8::Local<v8::Value> mongoLogout(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 1, "logout needs 1 arg") - std::shared_ptr<DBClientBase> conn = getConnection(scope, args); - const string db = toSTLString(args[0]); - BSONObj ret; - conn->logout(db, ret); - return scope->mongoToLZV8(ret, false); + try { + conn->auth(params); + } catch (const DBException& ex) { + return v8AssertionException(ex.toString()); } + return v8::Boolean::New(scope->getIsolate(), true); +} - /** - * get cursor from v8 argument - */ - mongo::DBClientCursor* getCursor(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - verify(scope->InternalCursorFT()->HasInstance(args.This())); - verify(args.This()->InternalFieldCount() == 1); - v8::Local<v8::External> c = - v8::Local<v8::External>::Cast(args.This()->GetInternalField(0)); - mongo::DBClientCursor* cursor = static_cast<mongo::DBClientCursor*>(c->Value()); - return cursor; - } +v8::Local<v8::Value> mongoLogout(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 1, "logout needs 1 arg") std::shared_ptr<DBClientBase> conn = + getConnection(scope, args); + const string db = toSTLString(args[0]); + BSONObj ret; + conn->logout(db, ret); + return scope->mongoToLZV8(ret, false); +} - v8::Local<v8::Value> internalCursorCons(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { +/** + * get cursor from v8 argument + */ +mongo::DBClientCursor* getCursor(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + verify(scope->InternalCursorFT()->HasInstance(args.This())); + verify(args.This()->InternalFieldCount() == 1); + v8::Local<v8::External> c = v8::Local<v8::External>::Cast(args.This()->GetInternalField(0)); + mongo::DBClientCursor* cursor = static_cast<mongo::DBClientCursor*>(c->Value()); + return cursor; +} + +v8::Local<v8::Value> internalCursorCons(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + return v8::Undefined(scope->getIsolate()); +} + +/** + * cursor.next() + */ +v8::Local<v8::Value> internalCursorNext(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + mongo::DBClientCursor* cursor = getCursor(scope, args); + if (!cursor) return v8::Undefined(scope->getIsolate()); - } + BSONObj o = cursor->next(); + bool ro = false; + if (args.This()->Has(v8::String::NewFromUtf8(scope->getIsolate(), "_ro"))) + ro = args.This()->Get(v8::String::NewFromUtf8(scope->getIsolate(), "_ro"))->BooleanValue(); + return scope->mongoToLZV8(o, ro); +} - /** - * cursor.next() - */ - v8::Local<v8::Value> internalCursorNext(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - mongo::DBClientCursor* cursor = getCursor(scope, args); - if (! cursor) - return v8::Undefined(scope->getIsolate()); - BSONObj o = cursor->next(); - bool ro = false; - if (args.This()->Has(v8::String::NewFromUtf8(scope->getIsolate(), "_ro"))) - ro = args.This()->Get(v8::String::NewFromUtf8(scope->getIsolate(), - "_ro"))->BooleanValue(); - return scope->mongoToLZV8(o, ro); - } +/** + * cursor.hasNext() + */ +v8::Local<v8::Value> internalCursorHasNext(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + mongo::DBClientCursor* cursor = getCursor(scope, args); + if (!cursor) + return v8::Boolean::New(scope->getIsolate(), false); + return v8::Boolean::New(scope->getIsolate(), cursor->more()); +} - /** - * cursor.hasNext() - */ - v8::Local<v8::Value> internalCursorHasNext(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - mongo::DBClientCursor* cursor = getCursor(scope, args); - if (! cursor) - return v8::Boolean::New(scope->getIsolate(), false); - return v8::Boolean::New(scope->getIsolate(), cursor->more()); - } +/** + * cursor.objsLeftInBatch() + */ +v8::Local<v8::Value> internalCursorObjsLeftInBatch( + V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + mongo::DBClientCursor* cursor = getCursor(scope, args); + if (!cursor) + return v8::Number::New(scope->getIsolate(), 0.0); + return v8::Number::New(scope->getIsolate(), static_cast<double>(cursor->objsLeftInBatch())); +} - /** - * cursor.objsLeftInBatch() - */ - v8::Local<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - mongo::DBClientCursor* cursor = getCursor(scope, args); - if (! cursor) - return v8::Number::New(scope->getIsolate(), 0.0); - return v8::Number::New(scope->getIsolate(), - static_cast<double>(cursor->objsLeftInBatch())); - } +/** + * cursor.readOnly() + */ +v8::Local<v8::Value> internalCursorReadOnly(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + verify(scope->InternalCursorFT()->HasInstance(args.This())); - /** - * cursor.readOnly() - */ - v8::Local<v8::Value> internalCursorReadOnly(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - verify(scope->InternalCursorFT()->HasInstance(args.This())); - - v8::Local<v8::Object> cursor = args.This(); - cursor->ForceSet(v8::String::NewFromUtf8(scope->getIsolate(), "_ro"), - v8::Boolean::New(scope->getIsolate(), true)); - return cursor; - } + v8::Local<v8::Object> cursor = args.This(); + cursor->ForceSet(v8::String::NewFromUtf8(scope->getIsolate(), "_ro"), + v8::Boolean::New(scope->getIsolate(), true)); + return cursor; +} - v8::Local<v8::Value> dbInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->DBFT()->GetFunction(); - return newInstance(f, args); - } +v8::Local<v8::Value> dbInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->DBFT()->GetFunction(); + return newInstance(f, args); + } - verify(scope->DBFT()->HasInstance(args.This())); + verify(scope->DBFT()->HasInstance(args.This())); - argumentCheck(args.Length() == 2, "db constructor requires 2 arguments") + argumentCheck(args.Length() == 2, "db constructor requires 2 arguments") args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]); - args.This()->ForceSet(scope->v8StringData("_name"), args[1]); + args.This()->ForceSet(scope->v8StringData("_name"), args[1]); - for (int i = 0; i < args.Length(); i++) { - argumentCheck(!args[i]->IsUndefined(), "db initializer called with undefined argument") - } + for (int i = 0; i < args.Length(); i++) { + argumentCheck(!args[i]->IsUndefined(), "db initializer called with undefined argument") + } - string dbName = toSTLString(args[1]); - if (!NamespaceString::validDBName(dbName)) { - return v8AssertionException(str::stream() << "[" << dbName - << "] is not a valid database name"); - } - return v8::Undefined(scope->getIsolate()); + string dbName = toSTLString(args[1]); + if (!NamespaceString::validDBName(dbName)) { + return v8AssertionException(str::stream() << "[" << dbName + << "] is not a valid database name"); } + return v8::Undefined(scope->getIsolate()); +} - v8::Local<v8::Value> collectionInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->DBCollectionFT()->GetFunction(); - return newInstance(f, args); - } +v8::Local<v8::Value> collectionInit(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->DBCollectionFT()->GetFunction(); + return newInstance(f, args); + } - verify(scope->DBCollectionFT()->HasInstance(args.This())); + verify(scope->DBCollectionFT()->HasInstance(args.This())); - argumentCheck(args.Length() == 4, "collection constructor requires 4 arguments") + argumentCheck(args.Length() == 4, "collection constructor requires 4 arguments") for (int i = 0; i < args.Length(); i++) { - argumentCheck(!args[i]->IsUndefined(), - "collection constructor called with undefined argument") - } - - args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]); - args.This()->ForceSet(scope->v8StringData("_db"), args[1]); - args.This()->ForceSet(scope->v8StringData("_shortName"), args[2]); - args.This()->ForceSet(v8::String::NewFromUtf8(scope->getIsolate(), "_fullName"), args[3]); - - auto context = scope->getOpContext(); - if (context && haveLocalShardingInfo(context->getClient(), toSTLString(args[3]))) { - return v8AssertionException("can't use sharded collection from db.eval"); - } - - return v8::Undefined(scope->getIsolate()); + argumentCheck(!args[i]->IsUndefined(), + "collection constructor called with undefined argument") } - v8::Local<v8::Value> dbQueryInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->DBQueryFT()->GetFunction(); - return newInstance(f, args); - } + args.This()->ForceSet(scope->v8StringData("_mongo"), args[0]); + args.This()->ForceSet(scope->v8StringData("_db"), args[1]); + args.This()->ForceSet(scope->v8StringData("_shortName"), args[2]); + args.This()->ForceSet(v8::String::NewFromUtf8(scope->getIsolate(), "_fullName"), args[3]); - verify(scope->DBQueryFT()->HasInstance(args.This())); - - argumentCheck(args.Length() >= 4, "dbQuery constructor requires at least 4 arguments") + auto context = scope->getOpContext(); + if (context && haveLocalShardingInfo(context->getClient(), toSTLString(args[3]))) { + return v8AssertionException("can't use sharded collection from db.eval"); + } - v8::Local<v8::Object> t = args.This(); - t->ForceSet(scope->v8StringData("_mongo"), args[0]); - t->ForceSet(scope->v8StringData("_db"), args[1]); - t->ForceSet(scope->v8StringData("_collection"), args[2]); - t->ForceSet(scope->v8StringData("_ns"), args[3]); - - if (args.Length() > 4 && args[4]->IsObject()) - t->ForceSet(scope->v8StringData("_query"), args[4]); - else - t->ForceSet(scope->v8StringData("_query"), v8::Object::New(scope->getIsolate())); - - if (args.Length() > 5 && args[5]->IsObject()) - t->ForceSet(scope->v8StringData("_fields"), args[5]); - else - t->ForceSet(scope->v8StringData("_fields"), v8::Null(scope->getIsolate())); - - if (args.Length() > 6 && args[6]->IsNumber()) - t->ForceSet(scope->v8StringData("_limit"), args[6]); - else - t->ForceSet(scope->v8StringData("_limit"), v8::Number::New(scope->getIsolate(), 0)); - - if (args.Length() > 7 && args[7]->IsNumber()) - t->ForceSet(scope->v8StringData("_skip"), args[7]); - else - t->ForceSet(scope->v8StringData("_skip"), v8::Number::New(scope->getIsolate(), 0)); - - if (args.Length() > 8 && args[8]->IsNumber()) - t->ForceSet(scope->v8StringData("_batchSize"), args[8]); - else - t->ForceSet(scope->v8StringData("_batchSize"), v8::Number::New(scope->getIsolate(), - 0)); - - if (args.Length() > 9 && args[9]->IsNumber()) - t->ForceSet(scope->v8StringData("_options"), args[9]); - else - t->ForceSet(scope->v8StringData("_options"), v8::Number::New(scope->getIsolate(), 0)); - - t->ForceSet(scope->v8StringData("_cursor"), v8::Null(scope->getIsolate())); - t->ForceSet(scope->v8StringData("_numReturned"), v8::Number::New(scope->getIsolate(), 0)); - t->ForceSet(scope->v8StringData("_special"), v8::Boolean::New(scope->getIsolate(), false)); + return v8::Undefined(scope->getIsolate()); +} - return v8::Undefined(scope->getIsolate()); +v8::Local<v8::Value> dbQueryInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->DBQueryFT()->GetFunction(); + return newInstance(f, args); } - void collectionSetter(v8::Local<v8::String> name, - v8::Local<v8::Value> value, - const v8::PropertyCallbackInfo<v8::Value>& info) { - v8::Local<v8::Value> val; - v8::ReturnValue<v8::Value> result = info.GetReturnValue(); - result.Set(val); - try { - V8Scope* scope = getScope(info.GetIsolate()); + verify(scope->DBQueryFT()->HasInstance(args.This())); - // Both DB and Collection objects use this setter - verify(scope->DBCollectionFT()->HasInstance(info.This()) - || scope->DBFT()->HasInstance(info.This())); + argumentCheck(args.Length() >= 4, "dbQuery constructor requires at least 4 arguments") - // a collection name cannot be overwritten by a variable - string sname = toSTLString(name); - if (sname.length() == 0 || sname[0] == '_') { - // if starts with '_' we allow overwrite - return; - } - // dont set - result.Set(value); - } - catch (const DBException& dbEx) { - result.Set(v8AssertionException(dbEx.toString())); - } - catch (...) { - result.Set(v8AssertionException("unknown error in collationSetter")); + v8::Local<v8::Object> t = args.This(); + t->ForceSet(scope->v8StringData("_mongo"), args[0]); + t->ForceSet(scope->v8StringData("_db"), args[1]); + t->ForceSet(scope->v8StringData("_collection"), args[2]); + t->ForceSet(scope->v8StringData("_ns"), args[3]); + + if (args.Length() > 4 && args[4]->IsObject()) + t->ForceSet(scope->v8StringData("_query"), args[4]); + else + t->ForceSet(scope->v8StringData("_query"), v8::Object::New(scope->getIsolate())); + + if (args.Length() > 5 && args[5]->IsObject()) + t->ForceSet(scope->v8StringData("_fields"), args[5]); + else + t->ForceSet(scope->v8StringData("_fields"), v8::Null(scope->getIsolate())); + + if (args.Length() > 6 && args[6]->IsNumber()) + t->ForceSet(scope->v8StringData("_limit"), args[6]); + else + t->ForceSet(scope->v8StringData("_limit"), v8::Number::New(scope->getIsolate(), 0)); + + if (args.Length() > 7 && args[7]->IsNumber()) + t->ForceSet(scope->v8StringData("_skip"), args[7]); + else + t->ForceSet(scope->v8StringData("_skip"), v8::Number::New(scope->getIsolate(), 0)); + + if (args.Length() > 8 && args[8]->IsNumber()) + t->ForceSet(scope->v8StringData("_batchSize"), args[8]); + else + t->ForceSet(scope->v8StringData("_batchSize"), v8::Number::New(scope->getIsolate(), 0)); + + if (args.Length() > 9 && args[9]->IsNumber()) + t->ForceSet(scope->v8StringData("_options"), args[9]); + else + t->ForceSet(scope->v8StringData("_options"), v8::Number::New(scope->getIsolate(), 0)); + + t->ForceSet(scope->v8StringData("_cursor"), v8::Null(scope->getIsolate())); + t->ForceSet(scope->v8StringData("_numReturned"), v8::Number::New(scope->getIsolate(), 0)); + t->ForceSet(scope->v8StringData("_special"), v8::Boolean::New(scope->getIsolate(), false)); + + return v8::Undefined(scope->getIsolate()); +} + +void collectionSetter(v8::Local<v8::String> name, + v8::Local<v8::Value> value, + const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::Value> val; + v8::ReturnValue<v8::Value> result = info.GetReturnValue(); + result.Set(val); + try { + V8Scope* scope = getScope(info.GetIsolate()); + + // Both DB and Collection objects use this setter + verify(scope->DBCollectionFT()->HasInstance(info.This()) || + scope->DBFT()->HasInstance(info.This())); + + // a collection name cannot be overwritten by a variable + string sname = toSTLString(name); + if (sname.length() == 0 || sname[0] == '_') { + // if starts with '_' we allow overwrite + return; } + // dont set + result.Set(value); + } catch (const DBException& dbEx) { + result.Set(v8AssertionException(dbEx.toString())); + } catch (...) { + result.Set(v8AssertionException("unknown error in collationSetter")); } +} - void collectionGetter(v8::Local<v8::String> name, - const v8::PropertyCallbackInfo<v8::Value>& info) { - v8::Local<v8::Value> val; - v8::ReturnValue<v8::Value> result = info.GetReturnValue(); - result.Set(val); - try { - V8Scope* scope = getScope(info.GetIsolate()); +void collectionGetter(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::Value> val; + v8::ReturnValue<v8::Value> result = info.GetReturnValue(); + result.Set(val); + try { + V8Scope* scope = getScope(info.GetIsolate()); - // Both DB and Collection objects use this getter - verify(scope->DBCollectionFT()->HasInstance(info.This()) - || scope->DBFT()->HasInstance(info.This())); + // Both DB and Collection objects use this getter + verify(scope->DBCollectionFT()->HasInstance(info.This()) || + scope->DBFT()->HasInstance(info.This())); - v8::TryCatch tryCatch; + v8::TryCatch tryCatch; - // first look in prototype, may be a function - v8::Local<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get(name); - if (!real->IsUndefined()) { - result.Set(real); - return; - } + // first look in prototype, may be a function + v8::Local<v8::Value> real = info.This()->GetPrototype()->ToObject()->Get(name); + if (!real->IsUndefined()) { + result.Set(real); + return; + } - // 2nd look into real values, may be cached collection object - string sname = toSTLString(name); - if (info.This()->HasRealNamedProperty(name)) { - v8::Local<v8::Value> prop = info.This()->GetRealNamedProperty(name); - if (prop->IsObject() && - prop->ToObject()->HasRealNamedProperty( - v8::String::NewFromUtf8(scope->getIsolate(), "_fullName"))) { - // need to check every time that the collection did not get sharded - auto context = scope->getOpContext(); - if (context && haveLocalShardingInfo(context->getClient(), toSTLString( - prop->ToObject()->GetRealNamedProperty( + // 2nd look into real values, may be cached collection object + string sname = toSTLString(name); + if (info.This()->HasRealNamedProperty(name)) { + v8::Local<v8::Value> prop = info.This()->GetRealNamedProperty(name); + if (prop->IsObject() && + prop->ToObject()->HasRealNamedProperty( + v8::String::NewFromUtf8(scope->getIsolate(), "_fullName"))) { + // need to check every time that the collection did not get sharded + auto context = scope->getOpContext(); + if (context && + haveLocalShardingInfo( + context->getClient(), + toSTLString(prop->ToObject()->GetRealNamedProperty( v8::String::NewFromUtf8(scope->getIsolate(), "_fullName"))))) { - result.Set( - v8AssertionException("can't use sharded collection from db.eval")); - return; - } + result.Set(v8AssertionException("can't use sharded collection from db.eval")); + return; } - result.Set(prop); - return; - } - else if (sname.length() == 0 || sname[0] == '_') { - // if starts with '_' we dont return collection, one must use getCollection() - return; - } - - // no hit, create new collection - v8::Local<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get( - v8::String::NewFromUtf8(scope->getIsolate(), "getCollection")); - if (! getCollection->IsFunction()) { - result.Set(v8AssertionException("getCollection is not a function")); - return; - } - - v8::Local<v8::Function> f = getCollection.As<v8::Function>(); - v8::Local<v8::Value> argv[1]; - argv[0] = name; - v8::Local<v8::Value> coll = f->Call(info.This(), 1, argv); - if (coll.IsEmpty()) { - result.Set(tryCatch.ReThrow()); - return; } - - uassert(16861, "getCollection returned something other than a collection", - scope->DBCollectionFT()->HasInstance(coll)); - - // cache collection for reuse, don't enumerate - info.This()->ForceSet(name, coll, v8::DontEnum); - result.Set(coll); + result.Set(prop); + return; + } else if (sname.length() == 0 || sname[0] == '_') { + // if starts with '_' we dont return collection, one must use getCollection() + return; } - catch (const DBException& dbEx) { - result.Set(v8AssertionException(dbEx.toString())); + + // no hit, create new collection + v8::Local<v8::Value> getCollection = info.This()->GetPrototype()->ToObject()->Get( + v8::String::NewFromUtf8(scope->getIsolate(), "getCollection")); + if (!getCollection->IsFunction()) { + result.Set(v8AssertionException("getCollection is not a function")); + return; } - catch (...) { - result.Set(v8AssertionException("unknown error in collectionGetter")); + + v8::Local<v8::Function> f = getCollection.As<v8::Function>(); + v8::Local<v8::Value> argv[1]; + argv[0] = name; + v8::Local<v8::Value> coll = f->Call(info.This(), 1, argv); + if (coll.IsEmpty()) { + result.Set(tryCatch.ReThrow()); + return; } + + uassert(16861, + "getCollection returned something other than a collection", + scope->DBCollectionFT()->HasInstance(coll)); + + // cache collection for reuse, don't enumerate + info.This()->ForceSet(name, coll, v8::DontEnum); + result.Set(coll); + } catch (const DBException& dbEx) { + result.Set(v8AssertionException(dbEx.toString())); + } catch (...) { + result.Set(v8AssertionException("unknown error in collectionGetter")); } +} - void dbQueryIndexAccess(unsigned int index, const v8::PropertyCallbackInfo<v8::Value>& info) { - v8::Local<v8::Value> val; - v8::ReturnValue<v8::Value> result = info.GetReturnValue(); - result.Set(val); - try { - V8Scope* scope = getScope(info.GetIsolate()); - verify(scope->DBQueryFT()->HasInstance(info.This())); +void dbQueryIndexAccess(unsigned int index, const v8::PropertyCallbackInfo<v8::Value>& info) { + v8::Local<v8::Value> val; + v8::ReturnValue<v8::Value> result = info.GetReturnValue(); + result.Set(val); + try { + V8Scope* scope = getScope(info.GetIsolate()); + verify(scope->DBQueryFT()->HasInstance(info.This())); + + v8::Local<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get( + v8::String::NewFromUtf8(scope->getIsolate(), "arrayAccess")); + massert(16660, "arrayAccess is not a function", arrayAccess->IsFunction()); + + v8::Local<v8::Function> f = arrayAccess.As<v8::Function>(); + v8::Local<v8::Value> argv[1]; + argv[0] = v8::Number::New(scope->getIsolate(), index); + + result.Set(f->Call(info.This(), 1, argv)); + } catch (const DBException& dbEx) { + result.Set(v8AssertionException(dbEx.toString())); + } catch (...) { + result.Set(v8AssertionException("unknown error in dbQueryIndexAccess")); + } +} - v8::Local<v8::Value> arrayAccess = info.This()->GetPrototype()->ToObject()->Get( - v8::String::NewFromUtf8(scope->getIsolate(), "arrayAccess")); - massert(16660, "arrayAccess is not a function", arrayAccess->IsFunction()); +v8::Local<v8::Value> objectIdInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->ObjectIdFT()->GetFunction(); + return newInstance(f, args); + } - v8::Local<v8::Function> f = arrayAccess.As<v8::Function>(); - v8::Local<v8::Value> argv[1]; - argv[0] = v8::Number::New(scope->getIsolate(), index); + v8::Local<v8::Object> it = args.This(); + verify(scope->ObjectIdFT()->HasInstance(it)); - result.Set(f->Call(info.This(), 1, argv)); - } - catch (const DBException& dbEx) { - result.Set(v8AssertionException(dbEx.toString())); - } - catch (...) { - result.Set(v8AssertionException("unknown error in dbQueryIndexAccess")); + OID oid; + if (args.Length() == 0) { + oid.init(); + } else { + string s = toSTLString(args[0]); + try { + Scope::validateObjectIdString(s); + } catch (const MsgAssertionException& m) { + return v8AssertionException(m.toString()); } + oid.init(s); } - v8::Local<v8::Value> objectIdInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->ObjectIdFT()->GetFunction(); - return newInstance(f, args); - } - - v8::Local<v8::Object> it = args.This(); - verify(scope->ObjectIdFT()->HasInstance(it)); - - OID oid; - if (args.Length() == 0) { - oid.init(); - } - else { - string s = toSTLString(args[0]); - try { - Scope::validateObjectIdString(s); - } - catch (const MsgAssertionException& m) { - return v8AssertionException(m.toString()); - } - oid.init(s); - } + it->ForceSet(scope->v8StringData("str"), + v8::String::NewFromUtf8(scope->getIsolate(), oid.toString().c_str())); + return it; +} - it->ForceSet(scope->v8StringData("str"), - v8::String::NewFromUtf8(scope->getIsolate(), oid.toString().c_str())); - return it; +v8::Local<v8::Value> dbRefInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->DBRefFT()->GetFunction(); + return newInstance(f, args); } - v8::Local<v8::Value> dbRefInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->DBRefFT()->GetFunction(); - return newInstance(f, args); - } - - v8::Local<v8::Object> it = args.This(); - verify(scope->DBRefFT()->HasInstance(it)); + v8::Local<v8::Object> it = args.This(); + verify(scope->DBRefFT()->HasInstance(it)); - argumentCheck(args.Length() >= 2 && args.Length() <= 3, "DBRef needs 2 or 3 arguments") + argumentCheck(args.Length() >= 2 && args.Length() <= 3, "DBRef needs 2 or 3 arguments") argumentCheck(args[0]->IsString(), "DBRef 1st parameter must be a string") - it->ForceSet(scope->v8StringData("$ref"), args[0]); - it->ForceSet(scope->v8StringData("$id"), args[1]); + it->ForceSet(scope->v8StringData("$ref"), args[0]); + it->ForceSet(scope->v8StringData("$id"), args[1]); - if (args.Length() == 3) { - argumentCheck(args[2]->IsString(), "DBRef 3rd parameter must be a string") + if (args.Length() == 3) { + argumentCheck(args[2]->IsString(), "DBRef 3rd parameter must be a string") it->ForceSet(scope->v8StringData("$db"), args[2]); - } - - return it; } - v8::Local<v8::Value> dbPointerInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->DBPointerFT()->GetFunction(); - return newInstance(f, args); - } + return it; +} - v8::Local<v8::Object> it = args.This(); - verify(scope->DBPointerFT()->HasInstance(it)); +v8::Local<v8::Value> dbPointerInit(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->DBPointerFT()->GetFunction(); + return newInstance(f, args); + } + + v8::Local<v8::Object> it = args.This(); + verify(scope->DBPointerFT()->HasInstance(it)); - argumentCheck(args.Length() == 2, "DBPointer needs 2 arguments") + argumentCheck(args.Length() == 2, "DBPointer needs 2 arguments") argumentCheck(args[0]->IsString(), "DBPointer 1st parameter must be a string") - argumentCheck(scope->ObjectIdFT()->HasInstance(args[1]), - "DBPointer 2nd parameter must be an ObjectId") + argumentCheck(scope->ObjectIdFT()->HasInstance(args[1]), + "DBPointer 2nd parameter must be an ObjectId") - it->ForceSet(scope->v8StringData("ns"), args[0]); - it->ForceSet(scope->v8StringData("id"), args[1]); - return it; - } + it->ForceSet(scope->v8StringData("ns"), args[0]); + it->ForceSet(scope->v8StringData("id"), args[1]); + return it; +} - v8::Local<v8::Value> dbTimestampInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->TimestampFT()->GetFunction(); - return newInstance(f, args); - } +v8::Local<v8::Value> dbTimestampInit(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->TimestampFT()->GetFunction(); + return newInstance(f, args); + } - v8::Local<v8::Object> it = args.This(); - verify(scope->TimestampFT()->HasInstance(it)); + v8::Local<v8::Object> it = args.This(); + verify(scope->TimestampFT()->HasInstance(it)); - if (args.Length() == 0) { - it->ForceSet(scope->v8StringData("t"), v8::Number::New(scope->getIsolate(), 0)); - it->ForceSet(scope->v8StringData("i"), v8::Number::New(scope->getIsolate(), 0)); + if (args.Length() == 0) { + it->ForceSet(scope->v8StringData("t"), v8::Number::New(scope->getIsolate(), 0)); + it->ForceSet(scope->v8StringData("i"), v8::Number::New(scope->getIsolate(), 0)); + } else if (args.Length() == 2) { + if (!args[0]->IsNumber()) { + return v8AssertionException("Timestamp time must be a number"); } - else if (args.Length() == 2) { - if (!args[0]->IsNumber()) { - return v8AssertionException("Timestamp time must be a number"); - } - if (!args[1]->IsNumber()) { - return v8AssertionException("Timestamp increment must be a number"); - } - int64_t t = args[0]->IntegerValue(); - int64_t largestVal = int64_t(OpTime::max().getSecs()); - if( t > largestVal ) - return v8AssertionException( str::stream() - << "The first argument must be in seconds; " - << t << " is too large (max " << largestVal << ")"); - it->ForceSet(scope->v8StringData("t"), args[0]); - it->ForceSet(scope->v8StringData("i"), args[1]); - } - else { - return v8AssertionException("Timestamp needs 0 or 2 arguments"); + if (!args[1]->IsNumber()) { + return v8AssertionException("Timestamp increment must be a number"); } - - return it; + int64_t t = args[0]->IntegerValue(); + int64_t largestVal = int64_t(OpTime::max().getSecs()); + if (t > largestVal) + return v8AssertionException(str::stream() << "The first argument must be in seconds; " + << t << " is too large (max " << largestVal + << ")"); + it->ForceSet(scope->v8StringData("t"), args[0]); + it->ForceSet(scope->v8StringData("i"), args[1]); + } else { + return v8AssertionException("Timestamp needs 0 or 2 arguments"); } - v8::Local<v8::Value> binDataInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->BinDataFT()->GetFunction(); - return newInstance(f, args); - } + return it; +} - v8::Local<v8::Object> it = args.This(); - verify(scope->BinDataFT()->HasInstance(it)); +v8::Local<v8::Value> binDataInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->BinDataFT()->GetFunction(); + return newInstance(f, args); + } - argumentCheck(args.Length() == 2, "BinData takes 2 arguments -- BinData(subtype,data)"); + v8::Local<v8::Object> it = args.This(); + verify(scope->BinDataFT()->HasInstance(it)); - // 2 args: type, base64 string - v8::Local<v8::Value> type = args[0]; - if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) { - return v8AssertionException( - "BinData subtype must be a Number between 0 and 255 inclusive)"); - } - v8::String::Utf8Value utf(args[1]); - // uassert if invalid base64 string - string tmpBase64 = base64::decode(*utf); - // length property stores the decoded length - it->ForceSet(scope->v8StringData("len"), - v8::Number::New(scope->getIsolate(), tmpBase64.length()), - v8::PropertyAttribute::ReadOnly); - it->ForceSet(scope->v8StringData("type"), type, v8::PropertyAttribute::ReadOnly); - it->SetInternalField(0, args[1]); - - return it; + argumentCheck(args.Length() == 2, "BinData takes 2 arguments -- BinData(subtype,data)"); + + // 2 args: type, base64 string + v8::Local<v8::Value> type = args[0]; + if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) { + return v8AssertionException( + "BinData subtype must be a Number between 0 and 255 inclusive)"); } + v8::String::Utf8Value utf(args[1]); + // uassert if invalid base64 string + string tmpBase64 = base64::decode(*utf); + // length property stores the decoded length + it->ForceSet(scope->v8StringData("len"), + v8::Number::New(scope->getIsolate(), tmpBase64.length()), + v8::PropertyAttribute::ReadOnly); + it->ForceSet(scope->v8StringData("type"), type, v8::PropertyAttribute::ReadOnly); + it->SetInternalField(0, args[1]); + + return it; +} - v8::Local<v8::Value> binDataToString(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - verify(scope->BinDataFT()->HasInstance(it)); - int type = it->Get(v8::String::NewFromUtf8(scope->getIsolate(), "type"))->Int32Value(); +v8::Local<v8::Value> binDataToString(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + verify(scope->BinDataFT()->HasInstance(it)); + int type = it->Get(v8::String::NewFromUtf8(scope->getIsolate(), "type"))->Int32Value(); + + stringstream ss; + verify(it->InternalFieldCount() == 1); + ss << "BinData(" << type << ",\"" << toSTLString(it->GetInternalField(0)) << "\")"; + return v8::String::NewFromUtf8(scope->getIsolate(), ss.str().c_str()); +} - stringstream ss; - verify(it->InternalFieldCount() == 1); - ss << "BinData(" << type << ",\"" << toSTLString(it->GetInternalField(0)) << "\")"; - return v8::String::NewFromUtf8(scope->getIsolate(), ss.str().c_str()); - } +v8::Local<v8::Value> binDataToBase64(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + verify(scope->BinDataFT()->HasInstance(it)); + verify(it->InternalFieldCount() == 1); + return it->GetInternalField(0); +} - v8::Local<v8::Value> binDataToBase64(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - verify(scope->BinDataFT()->HasInstance(it)); - verify(it->InternalFieldCount() == 1); - return it->GetInternalField(0); +v8::Local<v8::Value> binDataToHex(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + verify(scope->BinDataFT()->HasInstance(it)); + verify(it->InternalFieldCount() == 1); + string data = base64::decode(toSTLString(it->GetInternalField(0))); + stringstream ss; + ss.setf(ios_base::hex, ios_base::basefield); + ss.fill('0'); + ss.setf(ios_base::right, ios_base::adjustfield); + for (std::string::iterator it = data.begin(); it != data.end(); ++it) { + unsigned v = (unsigned char)*it; + ss << setw(2) << v; } + return v8::String::NewFromUtf8(scope->getIsolate(), ss.str().c_str()); +} - v8::Local<v8::Value> binDataToHex(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - verify(scope->BinDataFT()->HasInstance(it)); - verify(it->InternalFieldCount() == 1); - string data = base64::decode(toSTLString(it->GetInternalField(0))); - stringstream ss; - ss.setf (ios_base::hex, ios_base::basefield); - ss.fill ('0'); - ss.setf (ios_base::right, ios_base::adjustfield); - for(std::string::iterator it = data.begin(); it != data.end(); ++it) { - unsigned v = (unsigned char) *it; - ss << setw(2) << v; - } - return v8::String::NewFromUtf8(scope->getIsolate(), ss.str().c_str()); - } +static v8::Local<v8::Value> hexToBinData(V8Scope* scope, int type, string hexstr) { + // SERVER-9686: This function does not correctly check to make sure hexstr is actually made + // up of valid hex digits, and fails in the hex utility functions - static v8::Local<v8::Value> hexToBinData(V8Scope* scope, int type, string hexstr) { - // SERVER-9686: This function does not correctly check to make sure hexstr is actually made - // up of valid hex digits, and fails in the hex utility functions + int len = hexstr.length() / 2; + unique_ptr<char[]> data(new char[len]); + const char* src = hexstr.c_str(); + for (int i = 0; i < len; i++) { + data[i] = fromHex(src + i * 2); + } - int len = hexstr.length() / 2; - unique_ptr<char[]> data(new char[len]); - const char* src = hexstr.c_str(); - for(int i = 0; i < len; i++) { - data[i] = fromHex(src + i * 2); - } + string encoded = base64::encode(data.get(), len); + v8::Local<v8::Value> argv[2]; + argv[0] = v8::Number::New(scope->getIsolate(), type); + argv[1] = v8::String::NewFromUtf8(scope->getIsolate(), encoded.c_str()); + return scope->BinDataFT()->GetFunction()->NewInstance(2, argv); +} - string encoded = base64::encode(data.get(), len); - v8::Local<v8::Value> argv[2]; - argv[0] = v8::Number::New(scope->getIsolate(), type); - argv[1] = v8::String::NewFromUtf8(scope->getIsolate(), encoded.c_str()); - return scope->BinDataFT()->GetFunction()->NewInstance(2, argv); - } +v8::Local<v8::Value> uuidInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 1, "UUID needs 1 argument") v8::String::Utf8Value utf(args[0]); + argumentCheck(utf.length() == 32, + "UUID string must have 32 characters") return hexToBinData(scope, bdtUUID, *utf); +} - v8::Local<v8::Value> uuidInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 1, "UUID needs 1 argument") - v8::String::Utf8Value utf(args[0]); - argumentCheck(utf.length() == 32, "UUID string must have 32 characters") - return hexToBinData(scope, bdtUUID, *utf); - } +v8::Local<v8::Value> md5Init(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 1, "MD5 needs 1 argument") v8::String::Utf8Value utf(args[0]); + argumentCheck(utf.length() == 32, + "MD5 string must have 32 characters") return hexToBinData(scope, MD5Type, *utf); +} - v8::Local<v8::Value> md5Init(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 1, "MD5 needs 1 argument") - v8::String::Utf8Value utf(args[0]); - argumentCheck(utf.length() == 32, "MD5 string must have 32 characters") - return hexToBinData(scope, MD5Type, *utf); +v8::Local<v8::Value> hexDataInit(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 2, "HexData needs 2 arguments") v8::Local<v8::Value> type = + args[0]; + if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) { + return v8AssertionException("HexData subtype must be a Number between 0 and 255 inclusive"); } + v8::String::Utf8Value utf(args[1]); + return hexToBinData(scope, type->Int32Value(), *utf); +} - v8::Local<v8::Value> hexDataInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 2, "HexData needs 2 arguments") - v8::Local<v8::Value> type = args[0]; - if (!type->IsNumber() || type->Int32Value() < 0 || type->Int32Value() > 255) { - return v8AssertionException( - "HexData subtype must be a Number between 0 and 255 inclusive"); - } - v8::String::Utf8Value utf(args[1]); - return hexToBinData(scope, type->Int32Value(), *utf); +v8::Local<v8::Value> numberLongInit(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->NumberLongFT()->GetFunction(); + return newInstance(f, args); } - v8::Local<v8::Value> numberLongInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->NumberLongFT()->GetFunction(); - return newInstance(f, args); - } - - argumentCheck(args.Length() == 0 || args.Length() == 1 || args.Length() == 3, - "NumberLong needs 0, 1 or 3 arguments") + argumentCheck(args.Length() == 0 || args.Length() == 1 || args.Length() == 3, + "NumberLong needs 0, 1 or 3 arguments") v8::Local<v8::Object> it = args.This(); - verify(scope->NumberLongFT()->HasInstance(it)); - - if (args.Length() == 0) { - it->ForceSet(scope->v8StringData("floatApprox"), - v8::Number::New(scope->getIsolate(), 0)); - } - else if (args.Length() == 1) { - if (args[0]->IsNumber()) { - it->ForceSet(scope->v8StringData("floatApprox"), args[0]); + verify(scope->NumberLongFT()->HasInstance(it)); + + if (args.Length() == 0) { + it->ForceSet(scope->v8StringData("floatApprox"), v8::Number::New(scope->getIsolate(), 0)); + } else if (args.Length() == 1) { + if (args[0]->IsNumber()) { + it->ForceSet(scope->v8StringData("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&) { + return v8AssertionException(string("could not convert \"") + num + + "\" to NumberLong"); } - 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&) { - return v8AssertionException(string("could not convert \"") + - num + - "\" to NumberLong"); - } - unsigned long long val = n; - // values above 2^53 are not accurately represented in JS - if ((long long)val == - (long long)(double)(long long)(val) && val < 9007199254740992ULL) { - it->ForceSet(scope->v8StringData("floatApprox"), - v8::Number::New(scope->getIsolate(), (double)(long long)(val))); - } - else { - it->ForceSet(scope->v8StringData("floatApprox"), - v8::Number::New(scope->getIsolate(), (double)(long long)(val))); - it->ForceSet(scope->v8StringData("top"), - v8::Integer::New(scope->getIsolate(), val >> 32)); - it->ForceSet(scope->v8StringData("bottom"), - v8::Integer::New(scope->getIsolate(), - (unsigned long)(val & 0x00000000ffffffff))); - } + unsigned long long val = n; + // values above 2^53 are not accurately represented in JS + if ((long long)val == (long long)(double)(long long)(val) && + val < 9007199254740992ULL) { + it->ForceSet(scope->v8StringData("floatApprox"), + v8::Number::New(scope->getIsolate(), (double)(long long)(val))); + } else { + it->ForceSet(scope->v8StringData("floatApprox"), + v8::Number::New(scope->getIsolate(), (double)(long long)(val))); + it->ForceSet(scope->v8StringData("top"), + v8::Integer::New(scope->getIsolate(), val >> 32)); + it->ForceSet(scope->v8StringData("bottom"), + v8::Integer::New(scope->getIsolate(), + (unsigned long)(val & 0x00000000ffffffff))); } } - else { - it->ForceSet(scope->v8StringData("floatApprox"), args[0]->ToNumber()); - it->ForceSet(scope->v8StringData("top"), args[1]->ToUint32()); - it->ForceSet(scope->v8StringData("bottom"), args[2]->ToUint32()); - } - return it; + } else { + it->ForceSet(scope->v8StringData("floatApprox"), args[0]->ToNumber()); + it->ForceSet(scope->v8StringData("top"), args[1]->ToUint32()); + it->ForceSet(scope->v8StringData("bottom"), args[2]->ToUint32()); } + return it; +} - long long numberLongVal(V8Scope* scope, const v8::Local<v8::Object>& it) { - verify(scope->NumberLongFT()->HasInstance(it)); - if (!it->Has(v8::String::NewFromUtf8(scope->getIsolate(), "top"))) - return (long long)( - it->Get(v8::String::NewFromUtf8(scope->getIsolate(), - "floatApprox"))->NumberValue()); - return - (long long) - ((unsigned long long)(it->Get( - v8::String::NewFromUtf8(scope->getIsolate(),"top"))->ToInt32()->Value()) << 32) + - (unsigned)(it->Get( - v8::String::NewFromUtf8(scope->getIsolate(), "bottom"))->ToInt32()->Value()); - } +long long numberLongVal(V8Scope* scope, const v8::Local<v8::Object>& it) { + verify(scope->NumberLongFT()->HasInstance(it)); + if (!it->Has(v8::String::NewFromUtf8(scope->getIsolate(), "top"))) + return (long long)(it->Get(v8::String::NewFromUtf8(scope->getIsolate(), "floatApprox")) + ->NumberValue()); + return (long long)((unsigned long long)(it->Get(v8::String::NewFromUtf8(scope->getIsolate(), + "top")) + ->ToInt32() + ->Value()) + << 32) + + (unsigned)(it->Get(v8::String::NewFromUtf8(scope->getIsolate(), "bottom")) + ->ToInt32() + ->Value()); +} - v8::Local<v8::Value> numberLongValueOf(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - long long val = numberLongVal(scope, it); - return v8::Number::New(scope->getIsolate(), double(val)); - } +v8::Local<v8::Value> numberLongValueOf(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + long long val = numberLongVal(scope, it); + return v8::Number::New(scope->getIsolate(), double(val)); +} - v8::Local<v8::Value> numberLongToNumber(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - return numberLongValueOf(scope, args); - } +v8::Local<v8::Value> numberLongToNumber(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + return numberLongValueOf(scope, args); +} - v8::Local<v8::Value> numberLongToString(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); +v8::Local<v8::Value> numberLongToString(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); - stringstream ss; - long long val = numberLongVal(scope, it); - const long long limit = 2LL << 30; + stringstream ss; + long long val = numberLongVal(scope, it); + const long long limit = 2LL << 30; - if (val <= -limit || limit <= val) - ss << "NumberLong(\"" << val << "\")"; - else - ss << "NumberLong(" << val << ")"; + if (val <= -limit || limit <= val) + ss << "NumberLong(\"" << val << "\")"; + else + ss << "NumberLong(" << val << ")"; - string ret = ss.str(); - return v8::String::NewFromUtf8(scope->getIsolate(), ret.c_str()); - } + string ret = ss.str(); + return v8::String::NewFromUtf8(scope->getIsolate(), ret.c_str()); +} - v8::Local<v8::Value> numberIntInit(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - if (!args.IsConstructCall()) { - v8::Local<v8::Function> f = scope->NumberIntFT()->GetFunction(); - return newInstance(f, args); - } +v8::Local<v8::Value> numberIntInit(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + if (!args.IsConstructCall()) { + v8::Local<v8::Function> f = scope->NumberIntFT()->GetFunction(); + return newInstance(f, args); + } - v8::Local<v8::Object> it = args.This(); - verify(scope->NumberIntFT()->HasInstance(it)); + v8::Local<v8::Object> it = args.This(); + verify(scope->NumberIntFT()->HasInstance(it)); - argumentCheck(args.Length() == 0 || args.Length() == 1, "NumberInt needs 0 or 1 arguments") - if (args.Length() == 0) { - it->SetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt"), - v8::Number::New(scope->getIsolate(), 0)); - } - else if (args.Length() == 1) { - it->SetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt"), - args[0]->ToInt32()); - } - return it; + argumentCheck(args.Length() == 0 || args.Length() == 1, + "NumberInt needs 0 or 1 arguments") if (args.Length() == 0) { + it->SetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt"), + v8::Number::New(scope->getIsolate(), 0)); } - - int numberIntVal(V8Scope* scope, const v8::Local<v8::Object>& it) { - verify(scope->NumberIntFT()->HasInstance(it)); - v8::Local<v8::Value> value = - it->GetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt")); - verify(!value.IsEmpty()); - return value->Int32Value(); + else if (args.Length() == 1) { + it->SetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt"), + args[0]->ToInt32()); } + return it; +} - v8::Local<v8::Value> numberIntValueOf(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - return v8::Integer::New(scope->getIsolate(), numberIntVal(scope, it)); - } +int numberIntVal(V8Scope* scope, const v8::Local<v8::Object>& it) { + verify(scope->NumberIntFT()->HasInstance(it)); + v8::Local<v8::Value> value = + it->GetHiddenValue(v8::String::NewFromUtf8(scope->getIsolate(), "__NumberInt")); + verify(!value.IsEmpty()); + return value->Int32Value(); +} - v8::Local<v8::Value> numberIntToNumber(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - return numberIntValueOf(scope, args); - } +v8::Local<v8::Value> numberIntValueOf(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + return v8::Integer::New(scope->getIsolate(), numberIntVal(scope, it)); +} - v8::Local<v8::Value> numberIntToString(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - v8::Local<v8::Object> it = args.This(); - int val = numberIntVal(scope, it); - string ret = str::stream() << "NumberInt(" << val << ")"; - return v8::String::NewFromUtf8(scope->getIsolate(), ret.c_str()); - } +v8::Local<v8::Value> numberIntToNumber(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + return numberIntValueOf(scope, args); +} - v8::Local<v8::Value> v8ObjectInvalidForStorage(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 1, "invalidForStorage needs 1 argument") - if (args[0]->IsNull()) { - return v8::Null(scope->getIsolate()); - } - argumentCheck(args[0]->IsObject(), "argument to invalidForStorage has to be an object") - Status validForStorage = scope->v8ToMongo(args[0]->ToObject()).storageValid(true); - if (validForStorage.isOK()) { - return v8::Null(scope->getIsolate()); - } +v8::Local<v8::Value> numberIntToString(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + v8::Local<v8::Object> it = args.This(); + int val = numberIntVal(scope, it); + string ret = str::stream() << "NumberInt(" << val << ")"; + return v8::String::NewFromUtf8(scope->getIsolate(), ret.c_str()); +} - std::string errmsg = str::stream() << validForStorage.codeString() - << ": "<< validForStorage.reason(); - return v8::String::NewFromUtf8(scope->getIsolate(), errmsg.c_str()); +v8::Local<v8::Value> v8ObjectInvalidForStorage(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 1, "invalidForStorage needs 1 argument") if (args[0]->IsNull()) { + return v8::Null(scope->getIsolate()); } - - v8::Local<v8::Value> bsonsize(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 1, "bsonsize needs 1 argument") - if (args[0]->IsNull()) { - return v8::Number::New(scope->getIsolate(), 0); - } - argumentCheck(args[0]->IsObject(), "argument to bsonsize has to be an object") - return v8::Number::New(scope->getIsolate(), - scope->v8ToMongo(args[0]->ToObject()).objsize()); + argumentCheck(args[0]->IsObject(), "argument to invalidForStorage has to be an object") + Status validForStorage = scope->v8ToMongo(args[0]->ToObject()).storageValid(true); + if (validForStorage.isOK()) { + return v8::Null(scope->getIsolate()); } - v8::Local<v8::Value> bsonWoCompare(V8Scope* scope, - const v8::FunctionCallbackInfo<v8::Value>& args) { - argumentCheck(args.Length() == 2, "bsonWoCompare needs 2 argument"); + std::string errmsg = str::stream() << validForStorage.codeString() << ": " + << validForStorage.reason(); + return v8::String::NewFromUtf8(scope->getIsolate(), errmsg.c_str()); +} - argumentCheck(args[0]->IsObject(), "first argument to bsonWoCompare has to be an object"); - argumentCheck(args[1]->IsObject(), "second argument to bsonWoCompare has to be an object"); +v8::Local<v8::Value> bsonsize(V8Scope* scope, const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 1, "bsonsize needs 1 argument") if (args[0]->IsNull()) { + return v8::Number::New(scope->getIsolate(), 0); + } + argumentCheck(args[0]->IsObject(), "argument to bsonsize has to be an object") return v8:: + Number::New(scope->getIsolate(), scope->v8ToMongo(args[0]->ToObject()).objsize()); +} - BSONObj firstObject(scope->v8ToMongo(args[0]->ToObject())); - BSONObj secondObject(scope->v8ToMongo(args[1]->ToObject())); +v8::Local<v8::Value> bsonWoCompare(V8Scope* scope, + const v8::FunctionCallbackInfo<v8::Value>& args) { + argumentCheck(args.Length() == 2, "bsonWoCompare needs 2 argument"); - return v8::Number::New(scope->getIsolate(), firstObject.woCompare(secondObject)); - } + argumentCheck(args[0]->IsObject(), "first argument to bsonWoCompare has to be an object"); + argumentCheck(args[1]->IsObject(), "second argument to bsonWoCompare has to be an object"); + BSONObj firstObject(scope->v8ToMongo(args[0]->ToObject())); + BSONObj secondObject(scope->v8ToMongo(args[1]->ToObject())); + + return v8::Number::New(scope->getIsolate(), firstObject.woCompare(secondObject)); +} } |