summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorBen Becker <ben.becker@10gen.com>2013-01-18 14:15:28 -0800
committerBen Becker <ben.becker@10gen.com>2013-01-18 14:15:43 -0800
commit41c1110326ae00fc7fb279b3bfeabadc3a82bc5a (patch)
tree646e122504532957a3517ea1b3e82070c629d091 /src/mongo
parent98d2e5d364e01581a4ba1b2e7df25f79ebd836b2 (diff)
downloadmongo-41c1110326ae00fc7fb279b3bfeabadc3a82bc5a.tar.gz
SERVER-8104: clean up js global object
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/SConscript11
-rw-r--r--src/mongo/db/commands/group.cpp3
-rw-r--r--src/mongo/db/commands/mr.cpp3
-rw-r--r--src/mongo/db/dbeval.cpp2
-rw-r--r--src/mongo/db/matcher.cpp17
-rw-r--r--src/mongo/scripting/bench.cpp17
-rw-r--r--src/mongo/scripting/bench.h5
-rw-r--r--src/mongo/scripting/engine.cpp11
-rw-r--r--src/mongo/scripting/engine.h2
-rw-r--r--src/mongo/scripting/engine_v8.cpp135
-rw-r--r--src/mongo/scripting/engine_v8.h8
-rw-r--r--src/mongo/scripting/utils.cpp4
-rw-r--r--src/mongo/scripting/v8_db.cpp88
-rw-r--r--src/mongo/scripting/v8_db.h9
-rw-r--r--src/mongo/scripting/v8_utils.cpp8
-rw-r--r--src/mongo/scripting/v8_utils.h1
-rw-r--r--src/mongo/shell/assert.js227
-rw-r--r--src/mongo/shell/createCPPfromJavaScriptFiles.js8
-rw-r--r--src/mongo/shell/shell_utils.cpp1
-rw-r--r--src/mongo/shell/types.js598
-rw-r--r--src/mongo/shell/utils.js844
21 files changed, 1010 insertions, 992 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 41f57bbe999..8fe048ffe28 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -684,12 +684,15 @@ if darwin or env["_HAVEPCAP"]:
# --- shell ---
# if you add a file here, you need to add it in scripting/engine.cpp and shell/createCPPfromJavaScriptFiles.js as well
-env.JSHeader( "shell/mongo.cpp" ,
- [ "shell/utils.js","shell/utils_sh.js","shell/db.js","shell/mongo.js","shell/mr.js","shell/query.js","shell/collection.js"] )
+env.JSHeader("shell/mongo.cpp",
+ ["shell/assert.js", "shell/types.js", "shell/utils.js", "shell/utils_sh.js",
+ "shell/db.js", "shell/mongo.js", "shell/mr.js", "shell/query.js",
+ "shell/collection.js"])
# if you add a file here, you need to add it in shell/shell_utils.cpp and shell/createCPPfromJavaScriptFiles.js as well
-env.JSHeader( "shell/mongo-server.cpp" ,
- ["shell/servers.js", "shell/shardingtest.js", "shell/servers_misc.js", "shell/replsettest.js", "shell/replsetbridge.js"] )
+env.JSHeader("shell/mongo-server.cpp",
+ ["shell/servers.js", "shell/shardingtest.js",
+ "shell/servers_misc.js", "shell/replsettest.js", "shell/replsetbridge.js"])
coreShellFiles = [ "shell/dbshell.cpp",
"shell/shell_utils.cpp",
diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp
index 5d5f82cae9a..bd7b439620a 100644
--- a/src/mongo/db/commands/group.cpp
+++ b/src/mongo/db/commands/group.cpp
@@ -72,8 +72,7 @@ namespace mongo {
string& errmsg,
BSONObjBuilder& result ) {
- auto_ptr<Scope> s = globalScriptEngine->getPooledScope( realdbname );
- s->localConnect( realdbname.c_str() );
+ auto_ptr<Scope> s = globalScriptEngine->getPooledScope( realdbname + "group");
if ( reduceScope )
s->init( reduceScope );
diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp
index 7325c1f8596..a616fef7304 100644
--- a/src/mongo/db/commands/mr.cpp
+++ b/src/mongo/db/commands/mr.cpp
@@ -598,8 +598,7 @@ namespace mongo {
*/
void State::init() {
// setup js
- _scope.reset(globalScriptEngine->getPooledScope( _config.dbname ).release() );
- _scope->localConnect( _config.dbname.c_str() );
+ _scope.reset(globalScriptEngine->getPooledScope( _config.dbname + "mapreduce" ).release() );
if ( ! _config.scopeSetup.isEmpty() )
_scope->init( &_config.scopeSetup );
diff --git a/src/mongo/db/dbeval.cpp b/src/mongo/db/dbeval.cpp
index 4848279ebe3..056cafb9bdc 100644
--- a/src/mongo/db/dbeval.cpp
+++ b/src/mongo/db/dbeval.cpp
@@ -57,7 +57,7 @@ namespace mongo {
return false;
}
- auto_ptr<Scope> s = globalScriptEngine->getPooledScope( dbName );
+ auto_ptr<Scope> s = globalScriptEngine->getPooledScope( dbName + "dbeval" );
ScriptingFunction f = s->createFunction(code);
if ( f == 0 ) {
errmsg = (string)"compile failed: " + s->getError();
diff --git a/src/mongo/db/matcher.cpp b/src/mongo/db/matcher.cpp
index 5d814f4190d..2f2cb8b35e0 100644
--- a/src/mongo/db/matcher.cpp
+++ b/src/mongo/db/matcher.cpp
@@ -64,17 +64,8 @@ namespace mongo {
_func = 0;
_initCalled = false;
}
-
- ~Where() {
- if ( _scope.get() ){
- try {
- _scope->execSetup( "_mongo.readOnly = false;" , "make not read only" );
- }
- catch( DBException& e ){
- warning() << "javascript scope cleanup interrupted" << causedBy( e ) << endl;
- }
- }
+ ~Where() {
_func = 0;
}
@@ -83,14 +74,12 @@ namespace mongo {
return;
_initCalled = true;
- _scope = globalScriptEngine->getPooledScope( _ns );
+ _scope = globalScriptEngine->getPooledScope( _ns + "where" );
NamespaceString ns( _ns );
- _scope->localConnect( ns.db.c_str() );
-
+
massert( 10341 , "code has to be set first!" , ! _jsCode.empty() );
_func = _scope->createFunction( _jsCode.c_str() );
- _scope->execSetup( "_mongo.readOnly = true;" , "make read only" );
}
void setScope( const BSONObj& scope ) {
diff --git a/src/mongo/scripting/bench.cpp b/src/mongo/scripting/bench.cpp
index 234550586e6..f0256574afa 100644
--- a/src/mongo/scripting/bench.cpp
+++ b/src/mongo/scripting/bench.cpp
@@ -347,7 +347,7 @@ namespace mongo {
bool check = ! e["check"].eoo();
if( check ){
if ( e["check"].type() == CodeWScope || e["check"].type() == Code || e["check"].type() == String ) {
- scope = globalScriptEngine->getPooledScope( ns );
+ scope = globalScriptEngine->getPooledScope( ns + "benchrun" );
verify( scope.get() );
if ( e.type() == CodeWScope ) {
@@ -790,7 +790,7 @@ namespace mongo {
/**
* benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
*/
- BSONObj benchRunSync( const BSONObj& argsFake, void* data ) {
+ BSONObj BenchRunner::benchRunSync( const BSONObj& argsFake, void* data ) {
BSONObj start = benchStart( argsFake, data );
@@ -804,7 +804,7 @@ namespace mongo {
/**
* benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
*/
- BSONObj benchStart( const BSONObj& argsFake, void* data ) {
+ BSONObj BenchRunner::benchStart( const BSONObj& argsFake, void* data ) {
verify( argsFake.firstElement().isABSONObj() );
BSONObj args = argsFake.firstElement().Obj();
@@ -819,7 +819,7 @@ namespace mongo {
/**
* benchRun( { ops : [] , host : XXX , db : XXXX , parallel : 5 , seconds : 5 }
*/
- BSONObj benchFinish( const BSONObj& argsFake, void* data ) {
+ BSONObj BenchRunner::benchFinish( const BSONObj& argsFake, void* data ) {
OID oid = OID( argsFake.firstElement().String() );
@@ -831,11 +831,4 @@ namespace mongo {
return BSON( "" << finalObj );
}
- void installBenchmarkSystem( Scope& scope ) {
- scope.injectNative( "benchRun" , benchRunSync );
- scope.injectNative( "benchRunSync" , benchRunSync );
- scope.injectNative( "benchStart" , benchStart );
- scope.injectNative( "benchFinish" , benchFinish );
- }
-
-}
+} // namespace mongo
diff --git a/src/mongo/scripting/bench.h b/src/mongo/scripting/bench.h
index 7ae7d642f53..b3a644c7765 100644
--- a/src/mongo/scripting/bench.h
+++ b/src/mongo/scripting/bench.h
@@ -395,6 +395,11 @@ namespace mongo {
const BenchRunConfig &config() const { return *_config; } // TODO: Remove this function.
+ // JS bindings
+ static BSONObj benchFinish(const BSONObj& argsFake, void* data);
+ static BSONObj benchStart(const BSONObj& argsFake, void* data);
+ static BSONObj benchRunSync(const BSONObj& argsFake, void* data);
+
private:
// TODO: Same as for createWithConfig.
static boost::mutex _staticMutex;
diff --git a/src/mongo/scripting/engine.cpp b/src/mongo/scripting/engine.cpp
index 0124b45b45c..5017f40a4ed 100644
--- a/src/mongo/scripting/engine.cpp
+++ b/src/mongo/scripting/engine.cpp
@@ -24,6 +24,7 @@
#include "mongo/client/dbclientcursor.h"
#include "mongo/client/dbclientinterface.h"
+#include "mongo/scripting/bench.h"
#include "mongo/util/file.h"
namespace mongo {
@@ -230,7 +231,6 @@ namespace mongo {
}
void Scope::execCoreFiles() {
- // keeping same order as in SConstruct
execSetup(JSFiles::utils);
execSetup(JSFiles::utils_sh);
execSetup(JSFiles::db);
@@ -240,6 +240,14 @@ namespace mongo {
execSetup(JSFiles::collection);
}
+ /** install BenchRunner suite */
+ void Scope::installBenchRun() {
+ injectNative("benchRun", BenchRunner::benchRunSync);
+ injectNative("benchRunSync", BenchRunner::benchRunSync);
+ injectNative("benchStart", BenchRunner::benchStart);
+ injectNative("benchFinish", BenchRunner::benchFinish);
+ }
+
typedef map<string, list<Scope*> > PoolToScopes;
class ScopeCache {
@@ -378,6 +386,7 @@ namespace mongo {
Scope* _real;
};
+ /** Get a scope from the pool of scopes matching the supplied pool name */
auto_ptr<Scope> ScriptEngine::getPooledScope(const string& pool) {
if (!scopeCache.get())
scopeCache.reset(new ScopeCache());
diff --git a/src/mongo/scripting/engine.h b/src/mongo/scripting/engine.h
index e9d388145c0..160ba077962 100644
--- a/src/mongo/scripting/engine.h
+++ b/src/mongo/scripting/engine.h
@@ -71,6 +71,8 @@ namespace mongo {
virtual bool hasOutOfMemoryException() = 0;
+ virtual void installBenchRun();
+
virtual bool isKillPending() const = 0;
virtual void gc() = 0;
diff --git a/src/mongo/scripting/engine_v8.cpp b/src/mongo/scripting/engine_v8.cpp
index 88be725567c..534a74197f6 100644
--- a/src/mongo/scripting/engine_v8.cpp
+++ b/src/mongo/scripting/engine_v8.cpp
@@ -25,6 +25,12 @@ using namespace mongoutils;
namespace mongo {
+ // Generated symbols for JS files
+ namespace JSFiles {
+ extern const JSFile types;
+ extern const JSFile assert;
+ }
+
/**
* Unwraps a BSONObj from the JS wrapper
*/
@@ -501,17 +507,20 @@ namespace mongo {
internalFieldObjects->SetInternalFieldCount(1);
injectV8Function("print", Print);
- injectV8Function("version", Version);
- injectV8Function("load", load);
+ injectV8Function("version", Version); // TODO: remove
injectV8Function("gc", GCV8);
- injectV8Function("startCpuProfiler", startCpuProfiler);
- injectV8Function("stopCpuProfiler", stopCpuProfiler);
- injectV8Function("getCpuProfile", getCpuProfile);
+ // injectV8Function("startCpuProfiler", startCpuProfiler);
+ // injectV8Function("stopCpuProfiler", stopCpuProfiler);
+ // injectV8Function("getCpuProfile", getCpuProfile);
- // install db and bson types in the global scope
- installDBTypes(this, _global);
+ // install BSON functions in the global object
+ installBSONTypes();
- // install db/shell-specific utilities in the global scope
+ // load JS helpers (dependancy: installBSONTypes)
+ execSetup(JSFiles::assert);
+ execSetup(JSFiles::types);
+
+ // install process-specific utilities in the global scope (dependancy: types.js, assert.js)
if (_engine->_scopeInitCallback)
_engine->_scopeInitCallback(*this);
@@ -730,6 +739,40 @@ namespace mongo {
return v8ToMongo(v->ToObject());
}
+ v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit);
+ v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
+ scope->injectV8Function("valueOf", numberLongValueOf, proto);
+ scope->injectV8Function("toNumber", numberLongToNumber, proto);
+ scope->injectV8Function("toString", numberLongToString, proto);
+ return numberLong;
+ }
+
+ v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit);
+ v8::Local<v8::Template> proto = numberInt->PrototypeTemplate();
+ scope->injectV8Function("valueOf", numberIntValueOf, proto);
+ scope->injectV8Function("toNumber", numberIntToNumber, proto);
+ scope->injectV8Function("toString", numberIntToString, proto);
+ return numberInt;
+ }
+
+ v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit);
+ binData->InstanceTemplate()->SetInternalFieldCount(1);
+ v8::Local<v8::Template> proto = binData->PrototypeTemplate();
+ scope->injectV8Function("toString", binDataToString, proto);
+ scope->injectV8Function("base64", binDataToBase64, proto);
+ scope->injectV8Function("hex", binDataToHex, proto);
+ return binData;
+ }
+
+ v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) {
+ v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit);
+ ts->InstanceTemplate()->SetInternalFieldCount(1);
+ return ts;
+ }
+
// --- functions -----
bool hasFunctionIdentifier(const string& code) {
@@ -1012,14 +1055,17 @@ namespace mongo {
return;
uassert(12511, "localConnect previously called with a different name", false);
}
- _global->ForceSet(v8StringData("Mongo"),
- getMongoFunctionTemplate(this, true)->GetFunction());
- execCoreFiles();
- exec("_mongo = new Mongo();", "local connect 2", false, true, true, 0);
- exec((string)"db = _mongo.getDB(\"" + dbName + "\");", "local connect 3",
- false, true, true, 0);
- _connectState = LOCAL;
- _localDBName = dbName;
+
+ // NOTE: order is important here. the following methods must be called after
+ // the above conditional statements.
+
+ // install db access functions in the global object
+ installDBAccess();
+
+ // add global load() helper
+ injectV8Function("load", load);
+
+ // install the Mongo function object and instantiate the 'db' global
_global->ForceSet(v8StringData("Mongo"),
getMongoFunctionTemplate(this, true)->GetFunction());
execCoreFiles();
@@ -1038,13 +1084,70 @@ namespace mongo {
return;
if (_connectState == LOCAL)
uassert(12512, "localConnect already called, can't call externalSetup", false);
+
+ // install db access functions in the global object
+ installDBAccess();
+
+ // install thread-related functions (e.g. _threadInject)
installFork(this, _global, _context);
+
+ // install 'load' helper function
+ injectV8Function("load", load);
+
+ // install the Mongo function object
_global->ForceSet(v8StringData("Mongo"),
getMongoFunctionTemplate(this, false)->GetFunction());
execCoreFiles();
_connectState = EXTERNAL;
}
+ void V8Scope::installDBAccess() {
+ v8::Handle<v8::FunctionTemplate> db = createV8Function(dbInit);
+ db->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter);
+ _global->ForceSet(v8StringData("DB"), db->GetFunction());
+ v8::Handle<v8::FunctionTemplate> dbCollection = createV8Function(collectionInit);
+ dbCollection->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter,
+ collectionSetter);
+ _global->ForceSet(v8StringData("DBCollection"), dbCollection->GetFunction());
+
+ v8::Handle<v8::FunctionTemplate> dbQuery = createV8Function(dbQueryInit);
+ dbQuery->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
+ _global->ForceSet(v8StringData("DBQuery"), dbQuery->GetFunction());
+ }
+
+ void V8Scope::installBSONTypes() {
+ injectV8Function("ObjectId", objectIdInit, _global);
+ injectV8Function("DBRef", dbRefInit, _global);
+ injectV8Function("DBPointer", dbPointerInit, _global);
+
+ _global->ForceSet(v8StringData("BinData"),
+ getBinDataFunctionTemplate(this)->GetFunction());
+ _global->ForceSet(v8StringData("UUID"),
+ createV8Function(uuidInit)->GetFunction());
+ _global->ForceSet(v8StringData("MD5"),
+ createV8Function(md5Init)->GetFunction());
+ _global->ForceSet(v8StringData("HexData"),
+ createV8Function(hexDataInit)->GetFunction());
+ _global->ForceSet(v8StringData("NumberLong"),
+ getNumberLongFunctionTemplate(this)->GetFunction());
+ _global->ForceSet(v8StringData("NumberInt"),
+ getNumberIntFunctionTemplate(this)->GetFunction());
+ _global->ForceSet(v8StringData("Timestamp"),
+ getTimestampFunctionTemplate(this)->GetFunction());
+
+ BSONObjBuilder b;
+ b.appendMaxKey("");
+ b.appendMinKey("");
+ BSONObj o = b.obj();
+ BSONObjIterator i(o);
+ _global->ForceSet(v8StringData("MaxKey"), mongoToV8Element(i.next()));
+ _global->ForceSet(v8StringData("MinKey"), mongoToV8Element(i.next()));
+ _global->Get(v8StringData("Object"))->ToObject()->ForceSet(
+ v8StringData("bsonsize"),
+ createV8Function(bsonsize)->GetFunction());
+ }
+
+
// ----- internal -----
void V8Scope::reset() {
diff --git a/src/mongo/scripting/engine_v8.h b/src/mongo/scripting/engine_v8.h
index 2ece1eab79d..991e2f63fcd 100644
--- a/src/mongo/scripting/engine_v8.h
+++ b/src/mongo/scripting/engine_v8.h
@@ -91,10 +91,18 @@ namespace mongo {
/** check if there is a pending killOp request */
bool isKillPending() const;
+ /**
+ * Connect to a local database, create a Mongo object instance, and load any
+ * server-side js into the global object
+ */
virtual void localConnect(const char* dbName);
virtual void externalSetup();
+ virtual void installDBAccess();
+
+ virtual void installBSONTypes();
+
virtual string getError() { return _error; }
virtual bool hasOutOfMemoryException();
diff --git a/src/mongo/scripting/utils.cpp b/src/mongo/scripting/utils.cpp
index f3ae976d019..0ba7e900bcb 100644
--- a/src/mongo/scripting/utils.cpp
+++ b/src/mongo/scripting/utils.cpp
@@ -21,8 +21,6 @@
namespace mongo {
- void installBenchmarkSystem( Scope& scope );
-
static BSONObj native_hex_md5( const BSONObj& args, void* data ) {
uassert( 10261,
"hex_md5 takes a single string argument -- hex_md5(string)",
@@ -61,8 +59,6 @@ namespace mongo {
scope.injectNative( "hex_md5" , native_hex_md5 );
scope.injectNative( "version" , native_version );
scope.injectNative( "sleep" , native_sleep );
-
- installBenchmarkSystem( scope );
}
}
diff --git a/src/mongo/scripting/v8_db.cpp b/src/mongo/scripting/v8_db.cpp
index a0a8c8e58c6..e056dfbe206 100644
--- a/src/mongo/scripting/v8_db.cpp
+++ b/src/mongo/scripting/v8_db.cpp
@@ -102,94 +102,6 @@ namespace mongo {
return mongo;
}
- v8::Handle<v8::FunctionTemplate> getNumberLongFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> numberLong = scope->createV8Function(numberLongInit);
- v8::Local<v8::Template> proto = numberLong->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberLongValueOf, proto);
- scope->injectV8Function("toNumber", numberLongToNumber, proto);
- scope->injectV8Function("toString", numberLongToString, proto);
- return numberLong;
- }
-
- v8::Handle<v8::FunctionTemplate> getNumberIntFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> numberInt = scope->createV8Function(numberIntInit);
- v8::Local<v8::Template> proto = numberInt->PrototypeTemplate();
- scope->injectV8Function("valueOf", numberIntValueOf, proto);
- scope->injectV8Function("toNumber", numberIntToNumber, proto);
- scope->injectV8Function("toString", numberIntToString, proto);
- return numberInt;
- }
-
- v8::Handle<v8::FunctionTemplate> getBinDataFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> binData = scope->createV8Function(binDataInit);
- binData->InstanceTemplate()->SetInternalFieldCount(1);
- v8::Local<v8::Template> proto = binData->PrototypeTemplate();
- scope->injectV8Function("toString", binDataToString, proto);
- scope->injectV8Function("base64", binDataToBase64, proto);
- scope->injectV8Function("hex", binDataToHex, proto);
- return binData;
- }
-
- v8::Handle<v8::FunctionTemplate> getUUIDFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(uuidInit);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getMD5FunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(md5Init);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getHexDataFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> templ = scope->createV8Function(hexDataInit);
- return templ;
- }
-
- v8::Handle<v8::FunctionTemplate> getTimestampFunctionTemplate(V8Scope* scope) {
- v8::Handle<v8::FunctionTemplate> ts = scope->createV8Function(dbTimestampInit);
- ts->InstanceTemplate()->SetInternalFieldCount(1);
- return ts;
- }
-
- void installDBTypes(V8Scope* scope, v8::Handle<v8::Object>& global) {
- v8::Handle<v8::FunctionTemplate> db = scope->createV8Function(dbInit);
- db->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter, collectionSetter);
- global->ForceSet(scope->v8StringData("DB"), db->GetFunction());
- v8::Handle<v8::FunctionTemplate> dbCollection = scope->createV8Function(collectionInit);
- dbCollection->InstanceTemplate()->SetNamedPropertyHandler(collectionGetter,
- collectionSetter);
- global->ForceSet(scope->v8StringData("DBCollection"), dbCollection->GetFunction());
-
- v8::Handle<v8::FunctionTemplate> dbQuery = scope->createV8Function(dbQueryInit);
- dbQuery->InstanceTemplate()->SetIndexedPropertyHandler(dbQueryIndexAccess);
- global->ForceSet(scope->v8StringData("DBQuery"), dbQuery->GetFunction());
-
- scope->injectV8Function("ObjectId", objectIdInit, global);
- scope->injectV8Function("DBRef", dbRefInit, global);
- scope->injectV8Function("DBPointer", dbPointerInit, global);
-
- global->ForceSet(scope->v8StringData("BinData"), getBinDataFunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("UUID"), getUUIDFunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("MD5"), getMD5FunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("HexData"), getHexDataFunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("NumberLong"),
- getNumberLongFunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("NumberInt"),
- getNumberIntFunctionTemplate(scope)->GetFunction());
- global->ForceSet(scope->v8StringData("Timestamp"),
- getTimestampFunctionTemplate(scope)->GetFunction());
-
- BSONObjBuilder b;
- b.appendMaxKey("");
- b.appendMinKey("");
- BSONObj o = b.obj();
- BSONObjIterator i(o);
- global->ForceSet(scope->v8StringData("MaxKey"), scope->mongoToV8Element(i.next()));
- global->ForceSet(scope->v8StringData("MinKey"), scope->mongoToV8Element(i.next()));
- global->Get(scope->v8StringData("Object"))->ToObject()->ForceSet(scope->v8StringData("bsonsize"),
- scope->createV8Function(bsonsize)->GetFunction());
- }
-
void destroyConnection(v8::Persistent<v8::Value> self, void* parameter) {
delete static_cast<DBClientBase*>(parameter);
self.Dispose();
diff --git a/src/mongo/scripting/v8_db.h b/src/mongo/scripting/v8_db.h
index 6e8924465e4..2f747fd9714 100644
--- a/src/mongo/scripting/v8_db.h
+++ b/src/mongo/scripting/v8_db.h
@@ -27,9 +27,14 @@ namespace mongo {
class DBClientBase;
/**
- * install the db related functions and objects in the given scope
+ * install database access functions
*/
- void installDBTypes(V8Scope* scope, v8::Handle<v8::Object>& global);
+ void installDBAccess(V8Scope* scope);
+
+ /**
+ * install BSON types and helpers
+ */
+ void installBSONTypes(V8Scope* scope);
/**
* get the DBClientBase connection from JS args
diff --git a/src/mongo/scripting/v8_utils.cpp b/src/mongo/scripting/v8_utils.cpp
index 23f8f8e8980..de20f0713e1 100644
--- a/src/mongo/scripting/v8_utils.cpp
+++ b/src/mongo/scripting/v8_utils.cpp
@@ -41,6 +41,14 @@ namespace mongo {
return s;
}
+ /** Get the properties of an object (and it's prototype) as a comma-delimited string */
+ std::string v8objectToString(const v8::Handle<v8::Object>& o) {
+ v8::Local<v8::Array> properties = o->GetPropertyNames();
+ v8::String::Utf8Value str(properties);
+ massert(16696 , "error converting js type to Utf8Value", *str);
+ return std::string(*str, str.length());
+ }
+
std::string toSTLString(const v8::TryCatch* try_catch) {
stringstream ss;
v8::String::Utf8Value exception(try_catch->Exception());
diff --git a/src/mongo/scripting/v8_utils.h b/src/mongo/scripting/v8_utils.h
index ba271ffe787..1bdec4ae213 100644
--- a/src/mongo/scripting/v8_utils.h
+++ b/src/mongo/scripting/v8_utils.h
@@ -34,6 +34,7 @@ namespace mongo {
std::string toSTLString(const v8::Handle<v8::Value>& o);
std::string toSTLString(const v8::TryCatch* try_catch);
+ std::string v8ObjectToString(const v8::Handle<v8::Object>& o);
class V8Scope;
void installFork(V8Scope* scope,
diff --git a/src/mongo/shell/assert.js b/src/mongo/shell/assert.js
new file mode 100644
index 00000000000..b1279028307
--- /dev/null
+++ b/src/mongo/shell/assert.js
@@ -0,0 +1,227 @@
+doassert = function(msg) {
+ if (msg.indexOf("assert") == 0)
+ print(msg);
+ else
+ print("assert: " + msg);
+ printStackTrace();
+ throw msg;
+}
+
+assert = function(b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+ if (b)
+ return;
+ doassert(msg == undefined ? "assert failed" : "assert failed : " + msg);
+}
+
+assert.automsg = function(b) {
+ assert(eval(b), b);
+}
+
+assert._debug = false;
+
+assert.eq = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (a == b)
+ return;
+
+ if ((a != null && b != null) && friendlyEqual(a, b))
+ return;
+
+ doassert("[" + tojson(a) + "] != [" + tojson(b) + "] are not equal : " + msg);
+}
+
+assert.eq.automsg = function(a, b) {
+ assert.eq(eval(a), eval(b), "[" + a + "] != [" + b + "]");
+}
+
+assert.neq = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+ if (a != b)
+ return;
+
+ doassert("[" + a + "] != [" + b + "] are equal : " + msg);
+}
+
+assert.contains = function(o, arr, msg){
+ var wasIn = false
+
+ if(! arr.length){
+ for(var i in arr){
+ wasIn = arr[i] == o || ((arr[i] != null && o != null) && friendlyEqual(arr[i], o))
+ return;
+ if(wasIn) break
+ }
+ }
+ else {
+ for(var i = 0; i < arr.length; i++){
+ wasIn = arr[i] == o || ((arr[i] != null && o != null) && friendlyEqual(arr[i], o))
+ if(wasIn) break
+ }
+ }
+
+ if(! wasIn) doassert(tojson(o) + " was not in " + tojson(arr) + " : " + msg)
+}
+
+assert.repeat = function(f, msg, timeout, interval) {
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ var start = new Date();
+ timeout = timeout || 30000;
+ interval = interval || 200;
+ var last;
+ while(1) {
+
+ if (typeof(f) == "string"){
+ if (eval(f))
+ return;
+ }
+ else {
+ if (f())
+ return;
+ }
+
+ if ((new Date()).getTime() - start.getTime() > timeout)
+ break;
+ sleep(interval);
+ }
+}
+
+assert.soon = function(f, msg, timeout /*ms*/, interval) {
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ var start = new Date();
+ timeout = timeout || 30000;
+ interval = interval || 200;
+ var last;
+ while(1) {
+ if (typeof(f) == "string"){
+ if (eval(f))
+ return;
+ }
+ else {
+ if (f())
+ return;
+ }
+
+ diff = (new Date()).getTime() - start.getTime();
+ if (diff > timeout)
+ doassert("assert.soon failed: " + f + ", msg:" + msg);
+ sleep(interval);
+ }
+}
+
+assert.time = function(f, msg, timeout /*ms*/) {
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ var start = new Date();
+ timeout = timeout || 30000;
+ if (typeof(f) == "string"){
+ res = eval(f);
+ }
+ else {
+ res = f();
+ }
+
+ diff = (new Date()).getTime() - start.getTime();
+ if (diff > timeout)
+ doassert("assert.time failed timeout " + timeout + "ms took " + diff + "ms : " + f + ", msg:" + msg);
+ return res;
+}
+
+assert.throws = function(func, params, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+ if (params && typeof(params) == "string")
+ throw "2nd argument to assert.throws has to be an array"
+ try {
+ func.apply(null, params);
+ }
+ catch (e){
+ return e;
+ }
+ doassert("did not throw exception: " + msg);
+}
+
+assert.throws.automsg = function(func, params) {
+ assert.throws(func, params, func.toString());
+}
+
+assert.commandWorked = function(res, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (res.ok == 1)
+ return;
+ doassert("command failed: " + tojson(res) + " : " + msg);
+}
+
+assert.commandFailed = function(res, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (res.ok == 0)
+ return;
+ doassert("command worked when it should have failed: " + tojson(res) + " : " + msg);
+}
+
+assert.isnull = function(what, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (what == null)
+ return;
+ doassert("supposed to be null (" + (msg || "") + ") was: " + tojson(what));
+}
+
+assert.lt = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (a < b)
+ return;
+ doassert(a + " is not less than " + b + " : " + msg);
+}
+
+assert.gt = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (a > b)
+ return;
+ doassert(a + " is not greater than " + b + " : " + msg);
+}
+
+assert.lte = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (a <= b)
+ return;
+ doassert(a + " is not less than or eq " + b + " : " + msg);
+}
+
+assert.gte = function(a, b, msg){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if (a >= b)
+ return;
+ doassert(a + " is not greater than or eq " + b + " : " + msg);
+}
+
+assert.between = function(a, b, c, msg, inclusive){
+ if (assert._debug && msg) print("in assert for: " + msg);
+
+ if((inclusive == undefined || inclusive == true) &&
+ a <= b && b <= c) return;
+ else if(a < b && b < c) return;
+ doassert(b + " is not between " + a + " and " + c + " : " + msg);
+}
+
+assert.betweenIn = function(a, b, c, msg){ assert.between(a, b, c, msg, true) }
+assert.betweenEx = function(a, b, c, msg){ assert.between(a, b, c, msg, false) }
+
+assert.close = function(a, b, msg, places){
+ if (places === undefined) {
+ places = 4;
+ }
+ if (Math.round((a - b) * Math.pow(10, places)) === 0) {
+ return;
+ }
+ doassert(a + " is not equal to " + b + " within " + places +
+ " places, diff: " + (a-b) + " : " + msg);
+};
diff --git a/src/mongo/shell/createCPPfromJavaScriptFiles.js b/src/mongo/shell/createCPPfromJavaScriptFiles.js
index ecb6be2fb68..32d2fbbd044 100644
--- a/src/mongo/shell/createCPPfromJavaScriptFiles.js
+++ b/src/mongo/shell/createCPPfromJavaScriptFiles.js
@@ -101,5 +101,9 @@ var shell = new ActiveXObject( "WScript.Shell" );
shell.CurrentDirectory = WScript.Arguments.Unnamed.Item( 0 );
var fso = new ActiveXObject( "Scripting.FileSystemObject" );
-rebuildIfNeeded( fso, "shell/mongo.cpp", ["shell/utils.js", "shell/utils_sh.js", "shell/db.js", "shell/mongo.js", "shell/mr.js", "shell/query.js", "shell/collection.js"] );
-rebuildIfNeeded( fso, "shell/mongo-server.cpp", ["shell/servers.js", "shell/shardingtest.js", "shell/servers_misc.js", "shell/replsettest.js", "shell/replsetbridge.js"] );
+rebuildIfNeeded(fso, "shell/mongo.cpp", ["shell/assert.js", "shell/types.js", "shell/utils.js", "shell/utils_sh.js",
+ "shell/db.js", "shell/mongo.js", "shell/mr.js",
+ "shell/query.js", "shell/collection.js"]);
+rebuildIfNeeded(fso, "shell/mongo-server.cpp", ["shell/servers.js", "shell/shardingtest.js",
+ "shell/servers_misc.js", "shell/replsettest.js",
+ "shell/replsetbridge.js"]);
diff --git a/src/mongo/shell/shell_utils.cpp b/src/mongo/shell/shell_utils.cpp
index c106cbf6d6a..dce193c1a44 100644
--- a/src/mongo/shell/shell_utils.cpp
+++ b/src/mongo/shell/shell_utils.cpp
@@ -152,6 +152,7 @@ namespace mongo {
scope.execSetup(JSFiles::servers_misc);
scope.execSetup(JSFiles::replsettest);
scope.execSetup(JSFiles::replsetbridge);
+ scope.installBenchRun();
if ( !_dbConnect.empty() ) {
uassert( 12513, "connect failed", scope.exec( _dbConnect , "(connect)" , false , true , false ) );
diff --git a/src/mongo/shell/types.js b/src/mongo/shell/types.js
new file mode 100644
index 00000000000..f0da6cf0d0c
--- /dev/null
+++ b/src/mongo/shell/types.js
@@ -0,0 +1,598 @@
+// Date and time types
+if (typeof(Timestamp) != "undefined"){
+ Timestamp.prototype.tojson = function() {
+ return this.toString();
+ }
+
+ Timestamp.prototype.getTime = function() {
+ return this.t;
+ }
+
+ Timestamp.prototype.getInc = function() {
+ return this.i;
+ }
+
+ Timestamp.prototype.toString = function() {
+ return "Timestamp(" + this.t + ", " + this.i + ")";
+ }
+}
+else {
+ print("warning: no Timestamp class");
+}
+
+Date.timeFunc = function(theFunc, numTimes){
+ var start = new Date();
+ numTimes = numTimes || 1;
+ for (var i=0; i<numTimes; i++){
+ theFunc.apply(null, argumentsToArray(arguments).slice(2));
+ }
+
+ return (new Date()).getTime() - start.getTime();
+}
+
+Date.prototype.tojson = function(){
+ var UTC = 'UTC';
+ var year = this['get'+UTC+'FullYear']().zeroPad(4);
+ var month = (this['get'+UTC+'Month']() + 1).zeroPad(2);
+ var date = this['get'+UTC+'Date']().zeroPad(2);
+ var hour = this['get'+UTC+'Hours']().zeroPad(2);
+ var minute = this['get'+UTC+'Minutes']().zeroPad(2);
+ var sec = this['get'+UTC+'Seconds']().zeroPad(2)
+
+ if (this['get'+UTC+'Milliseconds']())
+ sec += '.' + this['get'+UTC+'Milliseconds']().zeroPad(3)
+
+ var ofs = 'Z';
+ // // print a non-UTC time
+ // var ofsmin = this.getTimezoneOffset();
+ // if (ofsmin != 0){
+ // ofs = ofsmin > 0 ? '-' : '+'; // This is correct
+ // ofs += (ofsmin/60).zeroPad(2)
+ // ofs += (ofsmin%60).zeroPad(2)
+ // }
+ return 'ISODate("'+year+'-'+month+'-'+date+'T'+hour+':'+minute+':'+sec+ofs+'")';
+}
+
+ISODate = function(isoDateStr){
+ if (!isoDateStr)
+ return new Date();
+
+ var isoDateRegex = /(\d{4})-?(\d{2})-?(\d{2})([T ](\d{2})(:?(\d{2})(:?(\d{2}(\.\d+)?))?)?(Z|([+-])(\d{2}):?(\d{2})?)?)?/;
+ var res = isoDateRegex.exec(isoDateStr);
+
+ if (!res)
+ throw "invalid ISO date";
+
+ var year = parseInt(res[1],10) || 1970; // this should always be present
+ var month = (parseInt(res[2],10) || 1) - 1;
+ var date = parseInt(res[3],10) || 0;
+ var hour = parseInt(res[5],10) || 0;
+ var min = parseInt(res[7],10) || 0;
+ var sec = parseFloat(res[9]) || 0;
+ var ms = Math.round((sec%1) * 1000)
+ sec -= ms/1000
+
+ var time = Date.UTC(year, month, date, hour, min, sec, ms);
+
+ if (res[11] && res[11] != 'Z'){
+ var ofs = 0;
+ ofs += (parseInt(res[13],10) || 0) * 60*60*1000; // hours
+ ofs += (parseInt(res[14],10) || 0) * 60*1000; // mins
+ if (res[12] == '+') // if ahead subtract
+ ofs *= -1;
+
+ time += ofs
+ }
+
+ return new Date(time);
+}
+
+// Regular Expression
+RegExp.escape = function(text){
+ return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
+}
+
+RegExp.prototype.tojson = RegExp.prototype.toString;
+
+// Array
+Array.contains = function(a, x){
+ for (var i=0; i<a.length; i++){
+ if (a[i] == x)
+ return true;
+ }
+ return false;
+}
+
+Array.unique = function(a){
+ var u = [];
+ for (var i=0; i<a.length; i++){
+ var o = a[i];
+ if (! Array.contains(u, o)){
+ u.push(o);
+ }
+ }
+ return u;
+}
+
+Array.shuffle = function(arr){
+ for (var i=0; i<arr.length-1; i++){
+ var pos = i+Random.randInt(arr.length-i);
+ var save = arr[i];
+ arr[i] = arr[pos];
+ arr[pos] = save;
+ }
+ return arr;
+}
+
+Array.tojson = function(a, indent, nolint){
+ var lineEnding = nolint ? " " : "\n";
+
+ if (!indent)
+ indent = "";
+ if (nolint)
+ indent = "";
+
+ if (a.length == 0) {
+ return "[ ]";
+ }
+
+ var s = "[" + lineEnding;
+ indent += "\t";
+ for (var i=0; i<a.length; i++){
+ s += indent + tojson(a[i], indent, nolint);
+ if (i < a.length - 1){
+ s += "," + lineEnding;
+ }
+ }
+ if (a.length == 0) {
+ s += indent;
+ }
+
+ indent = indent.substring(1);
+ s += lineEnding+indent+"]";
+ return s;
+}
+
+Array.fetchRefs = function(arr, coll){
+ var n = [];
+ for (var i=0; i<arr.length; i ++){
+ var z = arr[i];
+ if (coll && coll != z.getCollection())
+ continue;
+ n.push(z.fetch());
+ }
+ return n;
+}
+
+Array.sum = function(arr){
+ if (arr.length == 0)
+ return null;
+ var s = arr[0];
+ for (var i=1; i<arr.length; i++)
+ s += arr[i];
+ return s;
+}
+
+Array.avg = function(arr){
+ if (arr.length == 0)
+ return null;
+ return Array.sum(arr) / arr.length;
+}
+
+Array.stdDev = function(arr){
+ var avg = Array.avg(arr);
+ var sum = 0;
+
+ for (var i=0; i<arr.length; i++){
+ sum += Math.pow(arr[i] - avg, 2);
+ }
+
+ return Math.sqrt(sum / arr.length);
+}
+
+if (typeof Array.isArray != "function"){
+ Array.isArray = function(arr){
+ return arr != undefined && arr.constructor == Array
+ }
+}
+
+// Object
+Object.extend = function(dst, src, deep){
+ for (var k in src){
+ var v = src[k];
+ if (deep && typeof(v) == "object"){
+ if ("floatApprox" in v) { // convert NumberLong properly
+ eval("v = " + tojson(v));
+ } else {
+ v = Object.extend(typeof (v.length) == "number" ? [] : {}, v, true);
+ }
+ }
+ dst[k] = v;
+ }
+ return dst;
+}
+
+Object.merge = function(dst, src, deep){
+ var clone = Object.extend({}, dst, deep)
+ return Object.extend(clone, src, deep)
+}
+
+Object.keySet = function(o) {
+ var ret = new Array();
+ for(var i in o) {
+ if (!(i in o.__proto__ && o[ i ] === o.__proto__[ i ])) {
+ ret.push(i);
+ }
+ }
+ return ret;
+}
+
+// String
+String.prototype.trim = function() {
+ return this.replace(/^\s+|\s+$/g,"");
+}
+String.prototype.ltrim = function() {
+ return this.replace(/^\s+/,"");
+}
+String.prototype.rtrim = function() {
+ return this.replace(/\s+$/,"");
+}
+
+String.prototype.startsWith = function(str){
+ return this.indexOf(str) == 0
+}
+
+String.prototype.endsWith = function(str){
+ return new RegExp(RegExp.escape(str) + "$").test(this)
+}
+
+// Returns a copy padded with the provided character _chr_ so it becomes (at least) _length_
+// characters long.
+// No truncation is performed if the string is already longer than _length_.
+// @param length minimum length of the returned string
+// @param right if falsy add leading whitespace, otherwise add trailing whitespace
+// @param chr character to be used for padding, defaults to whitespace
+// @return the padded string
+String.prototype.pad = function(length, right, chr) {
+ if (typeof chr == 'undefined') chr = ' ';
+ var str = this;
+ for (var i = length - str.length; i > 0; i--) {
+ if (right) {
+ str = str + chr;
+ } else {
+ str = chr + str;
+ }
+ }
+ return str;
+}
+
+// Number
+Number.prototype.toPercentStr = function() {
+ return (this * 100).toFixed(2) + "%";
+}
+
+Number.prototype.zeroPad = function(width) {
+ return ('' + this).pad(width, false, '0');
+}
+
+// NumberLong
+if (! NumberLong.prototype) {
+ NumberLong.prototype = {}
+}
+
+NumberLong.prototype.tojson = function() {
+ return this.toString();
+}
+
+// NumberInt
+if (! NumberInt.prototype) {
+ NumberInt.prototype = {}
+}
+
+NumberInt.prototype.tojson = function() {
+ return this.toString();
+}
+
+// ObjectId
+if (! ObjectId.prototype)
+ ObjectId.prototype = {}
+
+ObjectId.prototype.toString = function(){
+ return "ObjectId(" + tojson(this.str) + ")";
+}
+
+ObjectId.prototype.tojson = function(){
+ return this.toString();
+}
+
+ObjectId.prototype.valueOf = function(){
+ return this.str;
+}
+
+ObjectId.prototype.isObjectId = true;
+
+ObjectId.prototype.getTimestamp = function(){
+ return new Date(parseInt(this.valueOf().slice(0,8), 16)*1000);
+}
+
+ObjectId.prototype.equals = function(other){
+ return this.str == other.str;
+}
+
+// DBPointer
+if (typeof(DBPointer) != "undefined"){
+ DBPointer.prototype.fetch = function(){
+ assert(this.ns, "need a ns");
+ assert(this.id, "need an id");
+ return db[ this.ns ].findOne({ _id : this.id });
+ }
+
+ DBPointer.prototype.tojson = function(indent){
+ return this.toString();
+ }
+
+ DBPointer.prototype.getCollection = function(){
+ return this.ns;
+ }
+
+ DBPointer.prototype.getId = function(){
+ return this.id;
+ }
+
+ DBPointer.prototype.toString = function(){
+ return "DBPointer(" + tojson(this.ns) + ", " + tojson(this.id) + ")";
+ }
+}
+else {
+ print("warning: no DBPointer");
+}
+
+// DBRef
+if (typeof(DBRef) != "undefined"){
+ DBRef.prototype.fetch = function(){
+ assert(this.$ref, "need a ns");
+ assert(this.$id, "need an id");
+ return db[ this.$ref ].findOne({ _id : this.$id });
+ }
+
+ DBRef.prototype.tojson = function(indent){
+ return this.toString();
+ }
+
+ DBRef.prototype.getCollection = function(){
+ return this.$ref;
+ }
+
+ DBRef.prototype.getRef = function(){
+ return this.$ref;
+ }
+
+ DBRef.prototype.getId = function(){
+ return this.$id;
+ }
+
+ DBRef.prototype.toString = function(){
+ return "DBRef(" + tojson(this.$ref) + ", " + tojson(this.$id) + ")";
+ }
+}
+else {
+ print("warning: no DBRef");
+}
+
+// BinData
+if (typeof(BinData) != "undefined"){
+ BinData.prototype.tojson = function() {
+ return this.toString();
+ }
+
+ BinData.prototype.subtype = function() {
+ return this.type;
+ }
+ BinData.prototype.length = function() {
+ return this.len;
+ }
+}
+else {
+ print("warning: no BinData class");
+}
+
+// Map
+if (typeof(Map) == "undefined"){
+ Map = function(){
+ this._data = {};
+ }
+}
+
+Map.hash = function(val){
+ if (! val)
+ return val;
+
+ switch (typeof(val)){
+ case 'string':
+ case 'number':
+ case 'date':
+ return val.toString();
+ case 'object':
+ case 'array':
+ var s = "";
+ for (var k in val){
+ s += k + val[k];
+ }
+ return s;
+ }
+
+ throw "can't hash : " + typeof(val);
+}
+
+Map.prototype.put = function(key, value){
+ var o = this._get(key);
+ var old = o.value;
+ o.value = value;
+ return old;
+}
+
+Map.prototype.get = function(key){
+ return this._get(key).value;
+}
+
+Map.prototype._get = function(key){
+ var h = Map.hash(key);
+ var a = this._data[h];
+ if (! a){
+ a = [];
+ this._data[h] = a;
+ }
+ for (var i=0; i<a.length; i++){
+ if (friendlyEqual(key, a[i].key)){
+ return a[i];
+ }
+ }
+ var o = { key : key, value : null };
+ a.push(o);
+ return o;
+}
+
+Map.prototype.values = function(){
+ var all = [];
+ for (var k in this._data){
+ this._data[k].forEach(function(z){ all.push(z.value); });
+ }
+ return all;
+}
+
+if (typeof(gc) == "undefined"){
+ gc = function(){
+ print("warning: using noop gc()");
+ }
+}
+
+// Free Functions
+tojsononeline = function(x){
+ return tojson(x, " ", true);
+}
+
+tojson = function(x, indent, nolint){
+ if (x === null)
+ return "null";
+
+ if (x === undefined)
+ return "undefined";
+
+ if (!indent)
+ indent = "";
+
+ switch (typeof x) {
+ case "string": {
+ var s = "\"";
+ for (var i=0; i<x.length; i++){
+ switch (x[i]){
+ case '"': s += '\\"'; break;
+ case '\\': s += '\\\\'; break;
+ case '\b': s += '\\b'; break;
+ case '\f': s += '\\f'; break;
+ case '\n': s += '\\n'; break;
+ case '\r': s += '\\r'; break;
+ case '\t': s += '\\t'; break;
+
+ default: {
+ var code = x.charCodeAt(i);
+ if (code < 0x20){
+ s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
+ } else {
+ s += x[i];
+ }
+ }
+ }
+ }
+ return s + "\"";
+ }
+ case "number":
+ case "boolean":
+ return "" + x;
+ case "object":{
+ var s = tojsonObject(x, indent, nolint);
+ if ((nolint == null || nolint == true) && s.length < 80 && (indent == null || indent.length == 0)){
+ s = s.replace(/[\s\r\n ]+/gm, " ");
+ }
+ return s;
+ }
+ case "function":
+ return x.toString();
+ default:
+ throw "tojson can't handle type " + (typeof x);
+ }
+
+}
+
+tojsonObject = function(x, indent, nolint){
+ var lineEnding = nolint ? " " : "\n";
+ var tabSpace = nolint ? "" : "\t";
+ assert.eq((typeof x), "object", "tojsonObject needs object, not [" + (typeof x) + "]");
+
+ if (!indent)
+ indent = "";
+
+ if (typeof(x.tojson) == "function" && x.tojson != tojson) {
+ return x.tojson(indent,nolint);
+ }
+
+ if (x.constructor && typeof(x.constructor.tojson) == "function" && x.constructor.tojson != tojson) {
+ return x.constructor.tojson(x, indent, nolint);
+ }
+
+ try {
+ // modify display of min/max key for spidermonkey
+ if (x.toString() == "[object MaxKey]")
+ return "{ $maxKey : 1 }";
+ if (x.toString() == "[object MinKey]")
+ return "{ $minKey : 1 }";
+ }
+ catch(e) {
+ // toString not callable
+ return "[object]";
+ }
+
+ var s = "{" + lineEnding;
+
+ // push one level of indent
+ indent += tabSpace;
+
+ var total = 0;
+ for (var k in x) total++;
+ if (total == 0) {
+ s += indent + lineEnding;
+ }
+
+ var keys = x;
+ if (typeof(x._simpleKeys) == "function")
+ keys = x._simpleKeys();
+ var num = 1;
+ for (var k in keys){
+ var val = x[k];
+ if (val == DB.prototype || val == DBCollection.prototype)
+ continue;
+
+ s += indent + "\"" + k + "\" : " + tojson(val, indent, nolint);
+ if (num != total) {
+ s += ",";
+ num++;
+ }
+ s += lineEnding;
+ }
+
+ // pop one level of indent
+ indent = indent.substring(1);
+ return s + indent + "}";
+}
+
+isString = function(x){
+ return typeof(x) == "string";
+}
+
+isNumber = function(x){
+ return typeof(x) == "number";
+}
+
+isObject = function(x){
+ return typeof(x) == "object";
+}
diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js
index b787838a704..1d95dffff8f 100644
--- a/src/mongo/shell/utils.js
+++ b/src/mongo/shell/utils.js
@@ -50,267 +50,6 @@ setVerboseShell = function( value ) {
_verboseShell = value;
}
-doassert = function (msg) {
- if (msg.indexOf("assert") == 0)
- print(msg);
- else
- print("assert: " + msg);
- printStackTrace();
- throw msg;
-}
-
-assert = function( b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
- if ( b )
- return;
- doassert( msg == undefined ? "assert failed" : "assert failed : " + msg );
-}
-
-// the mongo code uses verify
-// so this is to be nice to mongo devs
-verify = assert;
-
-assert.automsg = function( b ) {
- assert( eval( b ), b );
-}
-
-assert._debug = false;
-
-assert.eq = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( a == b )
- return;
-
- if ( ( a != null && b != null ) && friendlyEqual( a , b ) )
- return;
-
- doassert( "[" + tojson( a ) + "] != [" + tojson( b ) + "] are not equal : " + msg );
-}
-
-assert.eq.automsg = function( a, b ) {
- assert.eq( eval( a ), eval( b ), "[" + a + "] != [" + b + "]" );
-}
-
-assert.neq = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
- if ( a != b )
- return;
-
- doassert( "[" + a + "] != [" + b + "] are equal : " + msg );
-}
-
-assert.contains = function( o, arr, msg ){
- var wasIn = false
-
- if( ! arr.length ){
- for( var i in arr ){
- wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) )
- return;
- if( wasIn ) break
- }
- }
- else {
- for( var i = 0; i < arr.length; i++ ){
- wasIn = arr[i] == o || ( ( arr[i] != null && o != null ) && friendlyEqual( arr[i] , o ) )
- if( wasIn ) break
- }
- }
-
- if( ! wasIn ) doassert( tojson( o ) + " was not in " + tojson( arr ) + " : " + msg )
-}
-
-assert.repeat = function( f, msg, timeout, interval ) {
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- var start = new Date();
- timeout = timeout || 30000;
- interval = interval || 200;
- var last;
- while( 1 ) {
-
- if ( typeof( f ) == "string" ){
- if ( eval( f ) )
- return;
- }
- else {
- if ( f() )
- return;
- }
-
- if ( ( new Date() ).getTime() - start.getTime() > timeout )
- break;
- sleep( interval );
- }
-}
-
-assert.soon = function( f, msg, timeout /*ms*/, interval ) {
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- var start = new Date();
- timeout = timeout || 30000;
- interval = interval || 200;
- var last;
- while( 1 ) {
-
- if ( typeof( f ) == "string" ){
- if ( eval( f ) )
- return;
- }
- else {
- if ( f() )
- return;
- }
-
- diff = ( new Date() ).getTime() - start.getTime();
- if ( diff > timeout )
- doassert( "assert.soon failed: " + f + ", msg:" + msg );
- sleep( interval );
- }
-}
-
-assert.time = function( f, msg, timeout /*ms*/ ) {
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- var start = new Date();
- timeout = timeout || 30000;
-
- if ( typeof( f ) == "string" ){
- res = eval( f );
- }
- else {
- res = f();
- }
-
- diff = ( new Date() ).getTime() - start.getTime();
- if ( diff > timeout )
- doassert( "assert.time failed timeout " + timeout + "ms took " + diff + "ms : " + f + ", msg:" + msg );
- return res;
-}
-
-assert.throws = function( func , params , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( params && typeof( params ) == "string" )
- throw "2nd argument to assert.throws has to be an array"
-
- try {
- func.apply( null , params );
- }
- catch ( e ){
- return e;
- }
-
- doassert( "did not throw exception: " + msg );
-}
-
-assert.throws.automsg = function( func, params ) {
- assert.throws( func, params, func.toString() );
-}
-
-assert.commandWorked = function( res , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( res.ok == 1 )
- return;
-
- doassert( "command failed: " + tojson( res ) + " : " + msg );
-}
-
-assert.commandFailed = function( res , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( res.ok == 0 )
- return;
-
- doassert( "command worked when it should have failed: " + tojson( res ) + " : " + msg );
-}
-
-assert.isnull = function( what , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( what == null )
- return;
-
- doassert( "supposed to be null (" + ( msg || "" ) + ") was: " + tojson( what ) );
-}
-
-assert.lt = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( a < b )
- return;
- doassert( a + " is not less than " + b + " : " + msg );
-}
-
-assert.gt = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( a > b )
- return;
- doassert( a + " is not greater than " + b + " : " + msg );
-}
-
-assert.lte = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( a <= b )
- return;
- doassert( a + " is not less than or eq " + b + " : " + msg );
-}
-
-assert.gte = function( a , b , msg ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if ( a >= b )
- return;
- doassert( a + " is not greater than or eq " + b + " : " + msg );
-}
-
-assert.between = function( a, b, c, msg, inclusive ){
- if ( assert._debug && msg ) print( "in assert for: " + msg );
-
- if( ( inclusive == undefined || inclusive == true ) &&
- a <= b && b <= c ) return;
- else if( a < b && b < c ) return;
-
- doassert( b + " is not between " + a + " and " + c + " : " + msg );
-}
-
-assert.betweenIn = function( a, b, c, msg ){ assert.between( a, b, c, msg, true ) }
-assert.betweenEx = function( a, b, c, msg ){ assert.between( a, b, c, msg, false ) }
-
-assert.close = function( a , b , msg , places ){
- if (places === undefined) {
- places = 4;
- }
- if (Math.round((a - b) * Math.pow(10, places)) === 0) {
- return;
- }
- doassert( a + " is not equal to " + b + " within " + places +
- " places, diff: " + (a-b) + " : " + msg );
-};
-
-Object.extend = function( dst , src , deep ){
- for ( var k in src ){
- var v = src[k];
- if ( deep && typeof(v) == "object" ){
- if ( "floatApprox" in v ) { // convert NumberLong properly
- eval( "v = " + tojson( v ) );
- } else {
- v = Object.extend( typeof ( v.length ) == "number" ? [] : {} , v , true );
- }
- }
- dst[k] = v;
- }
- return dst;
-}
-
-Object.merge = function( dst, src, deep ){
- var clone = Object.extend( {}, dst, deep )
- return Object.extend( clone, src, deep )
-}
-
argumentsToArray = function( a ){
var arr = [];
for ( var i=0; i<a.length; i++ )
@@ -318,64 +57,6 @@ argumentsToArray = function( a ){
return arr;
}
-isString = function( x ){
- return typeof( x ) == "string";
-}
-
-isNumber = function(x){
- return typeof( x ) == "number";
-}
-
-isObject = function( x ){
- return typeof( x ) == "object";
-}
-
-String.prototype.trim = function() {
- return this.replace(/^\s+|\s+$/g,"");
-}
-String.prototype.ltrim = function() {
- return this.replace(/^\s+/,"");
-}
-String.prototype.rtrim = function() {
- return this.replace(/\s+$/,"");
-}
-
-String.prototype.startsWith = function (str){
- return this.indexOf(str) == 0
-}
-
-String.prototype.endsWith = function (str){
- return new RegExp( RegExp.escape(str) + "$" ).test( this )
-}
-
-// Returns a copy padded with the provided character _chr_ so it becomes (at least) _length_
-// characters long.
-// No truncation is performed if the string is already longer than _length_.
-// @param length minimum length of the returned string
-// @param right if falsy add leading whitespace, otherwise add trailing whitespace
-// @param chr character to be used for padding, defaults to whitespace
-// @return the padded string
-String.prototype.pad = function(length, right, chr) {
- if (typeof chr == 'undefined') chr = ' ';
- var str = this;
- for (var i = length - str.length; i > 0; i--) {
- if (right) {
- str = str + chr;
- } else {
- str = chr + str;
- }
- }
- return str;
-}
-
-Number.prototype.toPercentStr = function() {
- return (this * 100).toFixed(2) + "%";
-}
-
-Number.prototype.zeroPad = function(width) {
- return ('' + this).pad(width, false, '0');
-}
-
// Formats a simple stacked horizontal histogram bar in the shell.
// @param data array of the form [[ratio, symbol], ...] where ratio is between 0 and 1 and
// symbol is a string of length 1
@@ -399,191 +80,6 @@ _barFormat = function(data, width) {
return res;
}
-Date.timeFunc = function( theFunc , numTimes ){
-
- var start = new Date();
-
- numTimes = numTimes || 1;
- for ( var i=0; i<numTimes; i++ ){
- theFunc.apply( null , argumentsToArray( arguments ).slice( 2 ) );
- }
-
- return (new Date()).getTime() - start.getTime();
-}
-
-Date.prototype.tojson = function(){
-
- var UTC = Date.printAsUTC ? 'UTC' : '';
-
- var year = this['get'+UTC+'FullYear']().zeroPad(4);
- var month = (this['get'+UTC+'Month']() + 1).zeroPad(2);
- var date = this['get'+UTC+'Date']().zeroPad(2);
- var hour = this['get'+UTC+'Hours']().zeroPad(2);
- var minute = this['get'+UTC+'Minutes']().zeroPad(2);
- var sec = this['get'+UTC+'Seconds']().zeroPad(2)
-
- if (this['get'+UTC+'Milliseconds']())
- sec += '.' + this['get'+UTC+'Milliseconds']().zeroPad(3)
-
- var ofs = 'Z';
- if (!Date.printAsUTC){
- var ofsmin = this.getTimezoneOffset();
- if (ofsmin != 0){
- ofs = ofsmin > 0 ? '-' : '+'; // This is correct
- ofs += (ofsmin/60).zeroPad(2)
- ofs += (ofsmin%60).zeroPad(2)
- }
- }
-
- return 'ISODate("'+year+'-'+month+'-'+date+'T'+hour+':'+minute+':'+sec+ofs+'")';
-}
-
-Date.printAsUTC = true;
-
-
-ISODate = function(isoDateStr){
- if (!isoDateStr)
- return new Date();
-
- var isoDateRegex = /(\d{4})-?(\d{2})-?(\d{2})([T ](\d{2})(:?(\d{2})(:?(\d{2}(\.\d+)?))?)?(Z|([+-])(\d{2}):?(\d{2})?)?)?/;
- var res = isoDateRegex.exec(isoDateStr);
-
- if (!res)
- throw "invalid ISO date";
-
- var year = parseInt(res[1],10) || 1970; // this should always be present
- var month = (parseInt(res[2],10) || 1) - 1;
- var date = parseInt(res[3],10) || 0;
- var hour = parseInt(res[5],10) || 0;
- var min = parseInt(res[7],10) || 0;
- var sec = parseFloat(res[9]) || 0;
- var ms = Math.round((sec%1) * 1000)
- sec -= ms/1000
-
- var time = Date.UTC(year, month, date, hour, min, sec, ms);
-
- if (res[11] && res[11] != 'Z'){
- var ofs = 0;
- ofs += (parseInt(res[13],10) || 0) * 60*60*1000; // hours
- ofs += (parseInt(res[14],10) || 0) * 60*1000; // mins
- if (res[12] == '+') // if ahead subtract
- ofs *= -1;
-
- time += ofs
- }
-
- return new Date(time);
-}
-
-RegExp.escape = function( text ){
- return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
-}
-
-RegExp.prototype.tojson = RegExp.prototype.toString;
-
-Array.contains = function( a , x ){
- for ( var i=0; i<a.length; i++ ){
- if ( a[i] == x )
- return true;
- }
- return false;
-}
-
-Array.unique = function( a ){
- var u = [];
- for ( var i=0; i<a.length; i++){
- var o = a[i];
- if ( ! Array.contains( u , o ) ){
- u.push( o );
- }
- }
- return u;
-}
-
-Array.shuffle = function( arr ){
- for ( var i=0; i<arr.length-1; i++ ){
- var pos = i+Random.randInt(arr.length-i);
- var save = arr[i];
- arr[i] = arr[pos];
- arr[pos] = save;
- }
- return arr;
-}
-
-
-Array.tojson = function( a , indent , nolint ){
- var lineEnding = nolint ? " " : "\n";
-
- if (!indent)
- indent = "";
-
- if ( nolint )
- indent = "";
-
- if (a.length == 0) {
- return "[ ]";
- }
-
- var s = "[" + lineEnding;
- indent += "\t";
- for ( var i=0; i<a.length; i++){
- s += indent + tojson( a[i], indent , nolint );
- if ( i < a.length - 1 ){
- s += "," + lineEnding;
- }
- }
- if ( a.length == 0 ) {
- s += indent;
- }
-
- indent = indent.substring(1);
- s += lineEnding+indent+"]";
- return s;
-}
-
-Array.fetchRefs = function( arr , coll ){
- var n = [];
- for ( var i=0; i<arr.length; i ++){
- var z = arr[i];
- if ( coll && coll != z.getCollection() )
- continue;
- n.push( z.fetch() );
- }
-
- return n;
-}
-
-Array.sum = function( arr ){
- if ( arr.length == 0 )
- return null;
- var s = arr[0];
- for ( var i=1; i<arr.length; i++ )
- s += arr[i];
- return s;
-}
-
-Array.avg = function( arr ){
- if ( arr.length == 0 )
- return null;
- return Array.sum( arr ) / arr.length;
-}
-
-Array.stdDev = function( arr ){
- var avg = Array.avg( arr );
- var sum = 0;
-
- for ( var i=0; i<arr.length; i++ ){
- sum += Math.pow( arr[i] - avg , 2 );
- }
-
- return Math.sqrt( sum / arr.length );
-}
-
-if( typeof Array.isArray != "function" ){
- Array.isArray = function( arr ){
- return arr != undefined && arr.constructor == Array
- }
-}
//these two are helpers for Array.sort(func)
compare = function(l, r){ return (l == r ? 0 : (l < r ? -1 : 1)); }
@@ -593,155 +89,6 @@ compareOn = function(field){
return function(l, r) { return compare(l[field], r[field]); }
}
-Object.keySet = function( o ) {
- var ret = new Array();
- for( var i in o ) {
- if ( !( i in o.__proto__ && o[ i ] === o.__proto__[ i ] ) ) {
- ret.push( i );
- }
- }
- return ret;
-}
-
-if ( ! NumberLong.prototype ) {
- NumberLong.prototype = {}
-}
-
-NumberLong.prototype.tojson = function() {
- return this.toString();
-}
-
-if ( ! NumberInt.prototype ) {
- NumberInt.prototype = {}
-}
-
-NumberInt.prototype.tojson = function() {
- return this.toString();
-}
-
-if ( ! ObjectId.prototype )
- ObjectId.prototype = {}
-
-ObjectId.prototype.toString = function(){
- return "ObjectId(" + tojson(this.str) + ")";
-}
-
-ObjectId.prototype.tojson = function(){
- return this.toString();
-}
-
-ObjectId.prototype.valueOf = function(){
- return this.str;
-}
-
-ObjectId.prototype.isObjectId = true;
-
-ObjectId.prototype.getTimestamp = function(){
- return new Date(parseInt(this.valueOf().slice(0,8), 16)*1000);
-}
-
-ObjectId.prototype.equals = function( other){
- return this.str == other.str;
-}
-
-if ( typeof( DBPointer ) != "undefined" ){
- DBPointer.prototype.fetch = function(){
- assert( this.ns , "need a ns" );
- assert( this.id , "need an id" );
-
- return db[ this.ns ].findOne( { _id : this.id } );
- }
-
- DBPointer.prototype.tojson = function(indent){
- return this.toString();
- }
-
- DBPointer.prototype.getCollection = function(){
- return this.ns;
- }
-
- DBPointer.prototype.getId = function(){
- return this.id;
- }
-
- DBPointer.prototype.toString = function(){
- return "DBPointer(" + tojson(this.ns) + ", " + tojson(this.id) + ")";
- }
-}
-else {
- print( "warning: no DBPointer" );
-}
-
-if ( typeof( DBRef ) != "undefined" ){
- DBRef.prototype.fetch = function(){
- assert( this.$ref , "need a ns" );
- assert( this.$id , "need an id" );
-
- return db[ this.$ref ].findOne( { _id : this.$id } );
- }
-
- DBRef.prototype.tojson = function(indent){
- return this.toString();
- }
-
- DBRef.prototype.getCollection = function(){
- return this.$ref;
- }
-
- DBRef.prototype.getRef = function(){
- return this.$ref;
- }
-
- DBRef.prototype.getId = function(){
- return this.$id;
- }
-
- DBRef.prototype.toString = function(){
- return "DBRef(" + tojson(this.$ref) + ", " + tojson(this.$id) + ")";
- }
-}
-else {
- print( "warning: no DBRef" );
-}
-
-if ( typeof( Timestamp ) != "undefined" ){
- Timestamp.prototype.tojson = function () {
- return this.toString();
- }
-
- Timestamp.prototype.getTime = function () {
- return this.t;
- }
-
- Timestamp.prototype.getInc = function () {
- return this.i;
- }
-
- Timestamp.prototype.toString = function () {
- return "Timestamp(" + this.t + ", " + this.i + ")";
- }
-}
-else {
- print( "warning: no Timestamp class" );
-}
-
-if ( typeof( BinData ) != "undefined" ){
- BinData.prototype.tojson = function () {
- return this.toString();
- }
-
- BinData.prototype.subtype = function () {
- return this.type;
- }
-
- BinData.prototype.length = function () {
- return this.len;
- }
-}
-else {
- print( "warning: no BinData class" );
-}
-
if ( typeof _threadInject != "undefined" ){
//print( "fork() available!" );
@@ -974,126 +321,6 @@ if ( typeof _threadInject != "undefined" ){
}
}
-tojsononeline = function( x ){
- return tojson( x , " " , true );
-}
-
-tojson = function( x, indent , nolint ){
- if ( x === null )
- return "null";
-
- if ( x === undefined )
- return "undefined";
-
- if (!indent)
- indent = "";
-
- switch ( typeof x ) {
- case "string": {
- var s = "\"";
- for ( var i=0; i<x.length; i++ ){
- switch (x[i]){
- case '"': s += '\\"'; break;
- case '\\': s += '\\\\'; break;
- case '\b': s += '\\b'; break;
- case '\f': s += '\\f'; break;
- case '\n': s += '\\n'; break;
- case '\r': s += '\\r'; break;
- case '\t': s += '\\t'; break;
-
- default: {
- var code = x.charCodeAt(i);
- if (code < 0x20){
- s += (code < 0x10 ? '\\u000' : '\\u00') + code.toString(16);
- } else {
- s += x[i];
- }
- }
- }
- }
- return s + "\"";
- }
- case "number":
- case "boolean":
- return "" + x;
- case "object":{
- var s = tojsonObject( x, indent , nolint );
- if ( ( nolint == null || nolint == true ) && s.length < 80 && ( indent == null || indent.length == 0 ) ){
- s = s.replace( /[\s\r\n ]+/gm , " " );
- }
- return s;
- }
- case "function":
- return x.toString();
- default:
- throw "tojson can't handle type " + ( typeof x );
- }
-
-}
-
-tojsonObject = function( x, indent , nolint ){
- var lineEnding = nolint ? " " : "\n";
- var tabSpace = nolint ? "" : "\t";
-
- assert.eq( ( typeof x ) , "object" , "tojsonObject needs object, not [" + ( typeof x ) + "]" );
-
- if (!indent)
- indent = "";
-
- if ( typeof( x.tojson ) == "function" && x.tojson != tojson ) {
- return x.tojson(indent,nolint);
- }
-
- if ( x.constructor && typeof( x.constructor.tojson ) == "function" && x.constructor.tojson != tojson ) {
- return x.constructor.tojson( x, indent , nolint );
- }
-
- try {
- // modify display of min/max key for spidermonkey
- if ( x.toString() == "[object MaxKey]" )
- return "{ $maxKey : 1 }";
- if ( x.toString() == "[object MinKey]" )
- return "{ $minKey : 1 }";
- }
- catch(e) {
- // toString not callable
- return "[object]";
- }
-
- var s = "{" + lineEnding;
-
- // push one level of indent
- indent += tabSpace;
-
- var total = 0;
- for ( var k in x ) total++;
- if ( total == 0 ) {
- s += indent + lineEnding;
- }
-
- var keys = x;
- if ( typeof( x._simpleKeys ) == "function" )
- keys = x._simpleKeys();
- var num = 1;
- for ( var k in keys ){
-
- var val = x[k];
- if ( val == DB.prototype || val == DBCollection.prototype )
- continue;
-
- s += indent + "\"" + k + "\" : " + tojson( val, indent , nolint );
- if (num != total) {
- s += ",";
- num++;
- }
- s += lineEnding;
- }
-
- // pop one level of indent
- indent = indent.substring(1);
- return s + indent + "}";
-}
-
shellPrint = function( x ){
it = x;
if ( x != undefined )
@@ -1620,77 +847,6 @@ shellHelper.show = function (what) {
}
-if ( typeof( Map ) == "undefined" ){
- Map = function(){
- this._data = {};
- }
-}
-
-Map.hash = function( val ){
- if ( ! val )
- return val;
-
- switch ( typeof( val ) ){
- case 'string':
- case 'number':
- case 'date':
- return val.toString();
- case 'object':
- case 'array':
- var s = "";
- for ( var k in val ){
- s += k + val[k];
- }
- return s;
- }
-
- throw "can't hash : " + typeof( val );
-}
-
-Map.prototype.put = function( key , value ){
- var o = this._get( key );
- var old = o.value;
- o.value = value;
- return old;
-}
-
-Map.prototype.get = function( key ){
- return this._get( key ).value;
-}
-
-Map.prototype._get = function( key ){
- var h = Map.hash( key );
- var a = this._data[h];
- if ( ! a ){
- a = [];
- this._data[h] = a;
- }
-
- for ( var i=0; i<a.length; i++ ){
- if ( friendlyEqual( key , a[i].key ) ){
- return a[i];
- }
- }
- var o = { key : key , value : null };
- a.push( o );
- return o;
-}
-
-Map.prototype.values = function(){
- var all = [];
- for ( var k in this._data ){
- this._data[k].forEach( function(z){ all.push( z.value ); } );
- }
- return all;
-}
-
-if ( typeof( gc ) == "undefined" ){
- gc = function(){
- print( "warning: using noop gc()" );
- }
-}
-
-
Math.sigFig = function( x , N ){
if ( ! N ){
N = 3;