summaryrefslogtreecommitdiff
path: root/src/mongo/scripting
diff options
context:
space:
mode:
authorAdam Chelminski <adam.chelminski@mongodb.com>2016-08-05 11:49:17 -0400
committerAdam Chelminski <adam.chelminski@mongodb.com>2016-08-15 10:52:24 -0400
commitdf4248d69bd6643925d0e9cc62c6be3adf7750d7 (patch)
tree1f6b84bc55c83a7c981f74ed7483dc087b7b23f6 /src/mongo/scripting
parent9175ab505d970a6e97733a28e16496426d10f3ee (diff)
downloadmongo-df4248d69bd6643925d0e9cc62c6be3adf7750d7.tar.gz
SERVER-24146 Fix JSON.stringify regression, and add new "tostrictjson" shell util function for printing strict JSON
Diffstat (limited to 'src/mongo/scripting')
-rw-r--r--src/mongo/scripting/mozjs/bindata.cpp18
-rw-r--r--src/mongo/scripting/mozjs/bindata.h3
-rw-r--r--src/mongo/scripting/mozjs/internedstring.defs3
-rw-r--r--src/mongo/scripting/mozjs/maxkey.cpp10
-rw-r--r--src/mongo/scripting/mozjs/maxkey.h3
-rw-r--r--src/mongo/scripting/mozjs/minkey.cpp10
-rw-r--r--src/mongo/scripting/mozjs/minkey.h3
-rw-r--r--src/mongo/scripting/mozjs/numberdecimal.cpp12
-rw-r--r--src/mongo/scripting/mozjs/numberdecimal.h3
-rw-r--r--src/mongo/scripting/mozjs/numberint.cpp9
-rw-r--r--src/mongo/scripting/mozjs/numberint.h3
-rw-r--r--src/mongo/scripting/mozjs/numberlong.cpp12
-rw-r--r--src/mongo/scripting/mozjs/numberlong.h3
-rw-r--r--src/mongo/scripting/mozjs/oid.cpp12
-rw-r--r--src/mongo/scripting/mozjs/oid.h3
-rw-r--r--src/mongo/scripting/mozjs/regexp.cpp16
-rw-r--r--src/mongo/scripting/mozjs/regexp.h11
-rw-r--r--src/mongo/scripting/mozjs/timestamp.cpp15
-rw-r--r--src/mongo/scripting/mozjs/timestamp.h6
-rw-r--r--src/mongo/scripting/mozjs/wraptype.h29
-rw-r--r--src/mongo/scripting/utils.cpp16
21 files changed, 176 insertions, 24 deletions
diff --git a/src/mongo/scripting/mozjs/bindata.cpp b/src/mongo/scripting/mozjs/bindata.cpp
index d7bacb5558e..6632b1ed315 100644
--- a/src/mongo/scripting/mozjs/bindata.cpp
+++ b/src/mongo/scripting/mozjs/bindata.cpp
@@ -46,10 +46,11 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec BinDataInfo::methods[4] = {
+const JSFunctionSpec BinDataInfo::methods[5] = {
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(base64, BinDataInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(hex, BinDataInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toString, BinDataInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toJSON, BinDataInfo),
JS_FS_END,
};
@@ -163,6 +164,21 @@ void BinDataInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
+void BinDataInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ ObjectWrapper o(cx, args.thisv());
+
+ auto data_str = getEncoded(args.thisv());
+
+ std::stringstream ss;
+ ss << std::hex;
+ ss.width(2);
+ ss.fill('0');
+ ss << o.getNumber(InternedString::type);
+
+ ValueReader(cx, args.rval())
+ .fromBSON(BSON("$binary" << *data_str << "$type" << ss.str()), nullptr, false);
+}
+
void BinDataInfo::Functions::base64::call(JSContext* cx, JS::CallArgs args) {
auto str = getEncoded(args.thisv());
diff --git a/src/mongo/scripting/mozjs/bindata.h b/src/mongo/scripting/mozjs/bindata.h
index 57a4f158949..ae3c8f40c28 100644
--- a/src/mongo/scripting/mozjs/bindata.h
+++ b/src/mongo/scripting/mozjs/bindata.h
@@ -46,13 +46,14 @@ struct BinDataInfo : public BaseInfo {
MONGO_DECLARE_JS_FUNCTION(base64);
MONGO_DECLARE_JS_FUNCTION(hex);
MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
MONGO_DECLARE_JS_FUNCTION(HexData);
MONGO_DECLARE_JS_FUNCTION(MD5);
MONGO_DECLARE_JS_FUNCTION(UUID);
};
- static const JSFunctionSpec methods[4];
+ static const JSFunctionSpec methods[5];
static const JSFunctionSpec freeFunctions[4];
static const char* const className;
diff --git a/src/mongo/scripting/mozjs/internedstring.defs b/src/mongo/scripting/mozjs/internedstring.defs
index 40bf0b97498..792ec0bbcb5 100644
--- a/src/mongo/scripting/mozjs/internedstring.defs
+++ b/src/mongo/scripting/mozjs/internedstring.defs
@@ -18,6 +18,7 @@ MONGO_MOZJS_INTERNED_STRING(dollar_db, "$db")
MONGO_MOZJS_INTERNED_STRING(dollar_id, "$id")
MONGO_MOZJS_INTERNED_STRING(dollar_ref, "$ref")
MONGO_MOZJS_INTERNED_STRING(_fields, "_fields")
+MONGO_MOZJS_INTERNED_STRING(flags, "flags")
MONGO_MOZJS_INTERNED_STRING(floatApprox, "floatApprox")
MONGO_MOZJS_INTERNED_STRING(_fullName, "_fullName")
MONGO_MOZJS_INTERNED_STRING(getCollection, "getCollection")
@@ -37,6 +38,7 @@ MONGO_MOZJS_INTERNED_STRING(_ns, "_ns")
MONGO_MOZJS_INTERNED_STRING(ns, "ns")
MONGO_MOZJS_INTERNED_STRING(_numReturned, "_numReturned")
MONGO_MOZJS_INTERNED_STRING(_options, "_options")
+MONGO_MOZJS_INTERNED_STRING(prototype, "prototype")
MONGO_MOZJS_INTERNED_STRING(_query, "_query")
MONGO_MOZJS_INTERNED_STRING(readOnly, "readOnly")
MONGO_MOZJS_INTERNED_STRING(_ro, "_ro")
@@ -45,6 +47,7 @@ MONGO_MOZJS_INTERNED_STRING(_shortName, "_shortName")
MONGO_MOZJS_INTERNED_STRING(singleton, "singleton")
MONGO_MOZJS_INTERNED_STRING(_skip, "_skip")
MONGO_MOZJS_INTERNED_STRING(slaveOk, "slaveOk")
+MONGO_MOZJS_INTERNED_STRING(source, "source")
MONGO_MOZJS_INTERNED_STRING(_special, "_special")
MONGO_MOZJS_INTERNED_STRING(str, "str")
MONGO_MOZJS_INTERNED_STRING(top, "top")
diff --git a/src/mongo/scripting/mozjs/maxkey.cpp b/src/mongo/scripting/mozjs/maxkey.cpp
index 411f71dd746..db03b3ca555 100644
--- a/src/mongo/scripting/mozjs/maxkey.cpp
+++ b/src/mongo/scripting/mozjs/maxkey.cpp
@@ -39,8 +39,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec MaxKeyInfo::methods[2] = {
- MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MaxKeyInfo), JS_FS_END,
+const JSFunctionSpec MaxKeyInfo::methods[3] = {
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MaxKeyInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, MaxKeyInfo),
+ JS_FS_END,
};
const char* const MaxKeyInfo::className = "MaxKey";
@@ -88,6 +90,10 @@ void MaxKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData("{ \"$maxKey\" : 1 }");
}
+void MaxKeyInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ ValueReader(cx, args.rval()).fromBSON(BSON("$maxKey" << 1), nullptr, false);
+}
+
void MaxKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto) {
ObjectWrapper protoWrapper(cx, proto);
diff --git a/src/mongo/scripting/mozjs/maxkey.h b/src/mongo/scripting/mozjs/maxkey.h
index 32c567e9a68..4c9e5ac4abb 100644
--- a/src/mongo/scripting/mozjs/maxkey.h
+++ b/src/mongo/scripting/mozjs/maxkey.h
@@ -50,9 +50,10 @@ struct MaxKeyInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(tojson);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
};
- static const JSFunctionSpec methods[2];
+ static const JSFunctionSpec methods[3];
static void postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto);
diff --git a/src/mongo/scripting/mozjs/minkey.cpp b/src/mongo/scripting/mozjs/minkey.cpp
index c85ca2f6b25..7a5786559c5 100644
--- a/src/mongo/scripting/mozjs/minkey.cpp
+++ b/src/mongo/scripting/mozjs/minkey.cpp
@@ -39,8 +39,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec MinKeyInfo::methods[2] = {
- MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MinKeyInfo), JS_FS_END,
+const JSFunctionSpec MinKeyInfo::methods[3] = {
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(tojson, MinKeyInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, MinKeyInfo),
+ JS_FS_END,
};
const char* const MinKeyInfo::className = "MinKey";
@@ -88,6 +90,10 @@ void MinKeyInfo::Functions::tojson::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData("{ \"$minKey\" : 1 }");
}
+void MinKeyInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ ValueReader(cx, args.rval()).fromBSON(BSON("$minKey" << 1), nullptr, false);
+}
+
void MinKeyInfo::postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto) {
ObjectWrapper protoWrapper(cx, proto);
diff --git a/src/mongo/scripting/mozjs/minkey.h b/src/mongo/scripting/mozjs/minkey.h
index 62259747494..439e2a924d1 100644
--- a/src/mongo/scripting/mozjs/minkey.h
+++ b/src/mongo/scripting/mozjs/minkey.h
@@ -50,9 +50,10 @@ struct MinKeyInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(tojson);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
};
- static const JSFunctionSpec methods[2];
+ static const JSFunctionSpec methods[3];
static void postInstall(JSContext* cx, JS::HandleObject global, JS::HandleObject proto);
diff --git a/src/mongo/scripting/mozjs/numberdecimal.cpp b/src/mongo/scripting/mozjs/numberdecimal.cpp
index e5243eb6c8e..fcbdf2471c9 100644
--- a/src/mongo/scripting/mozjs/numberdecimal.cpp
+++ b/src/mongo/scripting/mozjs/numberdecimal.cpp
@@ -42,8 +42,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec NumberDecimalInfo::methods[2] = {
- MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberDecimalInfo), JS_FS_END,
+const JSFunctionSpec NumberDecimalInfo::methods[3] = {
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberDecimalInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, NumberDecimalInfo),
+ JS_FS_END,
};
const char* const NumberDecimalInfo::className = "NumberDecimal";
@@ -76,6 +78,12 @@ void NumberDecimalInfo::Functions::toString::call(JSContext* cx, JS::CallArgs ar
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
+void NumberDecimalInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ Decimal128 val = NumberDecimalInfo::ToNumberDecimal(cx, args.thisv());
+
+ ValueReader(cx, args.rval()).fromBSON(BSON("$numberDecimal" << val.toString()), nullptr, false);
+}
+
void NumberDecimalInfo::construct(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
diff --git a/src/mongo/scripting/mozjs/numberdecimal.h b/src/mongo/scripting/mozjs/numberdecimal.h
index 698bd8fe212..19460158cbe 100644
--- a/src/mongo/scripting/mozjs/numberdecimal.h
+++ b/src/mongo/scripting/mozjs/numberdecimal.h
@@ -46,9 +46,10 @@ struct NumberDecimalInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
};
- static const JSFunctionSpec methods[2];
+ static const JSFunctionSpec methods[3];
static const char* const className;
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/scripting/mozjs/numberint.cpp b/src/mongo/scripting/mozjs/numberint.cpp
index c55510502e9..b4d6af63155 100644
--- a/src/mongo/scripting/mozjs/numberint.cpp
+++ b/src/mongo/scripting/mozjs/numberint.cpp
@@ -40,9 +40,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec NumberIntInfo::methods[4] = {
+const JSFunctionSpec NumberIntInfo::methods[5] = {
MONGO_ATTACH_JS_CONSTRAINED_METHOD(toNumber, NumberIntInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberIntInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, NumberIntInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD(valueOf, NumberIntInfo),
JS_FS_END,
};
@@ -87,6 +88,12 @@ void NumberIntInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args)
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
+void NumberIntInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ int val = NumberIntInfo::ToNumberInt(cx, args.thisv());
+
+ args.rval().setInt32(val);
+}
+
void NumberIntInfo::construct(JSContext* cx, JS::CallArgs args) {
auto scope = getScope(cx);
diff --git a/src/mongo/scripting/mozjs/numberint.h b/src/mongo/scripting/mozjs/numberint.h
index a9a052bb0b7..7dd2538ba30 100644
--- a/src/mongo/scripting/mozjs/numberint.h
+++ b/src/mongo/scripting/mozjs/numberint.h
@@ -45,10 +45,11 @@ struct NumberIntInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(toNumber);
MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
MONGO_DECLARE_JS_FUNCTION(valueOf);
};
- static const JSFunctionSpec methods[4];
+ static const JSFunctionSpec methods[5];
static const char* const className;
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/scripting/mozjs/numberlong.cpp b/src/mongo/scripting/mozjs/numberlong.cpp
index 7bc9ebe10ff..1f763e47c20 100644
--- a/src/mongo/scripting/mozjs/numberlong.cpp
+++ b/src/mongo/scripting/mozjs/numberlong.cpp
@@ -43,9 +43,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec NumberLongInfo::methods[5] = {
+const JSFunctionSpec NumberLongInfo::methods[6] = {
MONGO_ATTACH_JS_CONSTRAINED_METHOD(toNumber, NumberLongInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD(toString, NumberLongInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, NumberLongInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD(valueOf, NumberLongInfo),
MONGO_ATTACH_JS_CONSTRAINED_METHOD(compare, NumberLongInfo),
JS_FS_END};
@@ -53,7 +54,7 @@ const JSFunctionSpec NumberLongInfo::methods[5] = {
const char* const NumberLongInfo::className = "NumberLong";
void NumberLongInfo::finalize(JSFreeOp* fop, JSObject* obj) {
- auto numLong = static_cast<int*>(JS_GetPrivate(obj));
+ auto numLong = static_cast<int64_t*>(JS_GetPrivate(obj));
if (numLong)
delete numLong;
@@ -94,6 +95,13 @@ void NumberLongInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args)
ValueReader(cx, args.rval()).fromStringData(ss.operator std::string());
}
+void NumberLongInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ int64_t val = NumberLongInfo::ToNumberLong(cx, args.thisv());
+
+ ValueReader(cx, args.rval())
+ .fromBSON(BSON("$numberLong" << std::to_string(val)), nullptr, false);
+}
+
void NumberLongInfo::Functions::compare::call(JSContext* cx, JS::CallArgs args) {
uassert(ErrorCodes::BadValue, "NumberLong.compare() needs 1 argument", args.length() == 1);
uassert(ErrorCodes::BadValue,
diff --git a/src/mongo/scripting/mozjs/numberlong.h b/src/mongo/scripting/mozjs/numberlong.h
index 22bf2b94790..ed2d850464b 100644
--- a/src/mongo/scripting/mozjs/numberlong.h
+++ b/src/mongo/scripting/mozjs/numberlong.h
@@ -56,6 +56,7 @@ struct NumberLongInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(toNumber);
MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
MONGO_DECLARE_JS_FUNCTION(valueOf);
MONGO_DECLARE_JS_FUNCTION(compare);
MONGO_DECLARE_JS_FUNCTION(floatApprox);
@@ -63,7 +64,7 @@ struct NumberLongInfo : public BaseInfo {
MONGO_DECLARE_JS_FUNCTION(bottom);
};
- static const JSFunctionSpec methods[5];
+ static const JSFunctionSpec methods[6];
static const char* const className;
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/scripting/mozjs/oid.cpp b/src/mongo/scripting/mozjs/oid.cpp
index afd6345441a..f2db6c80383 100644
--- a/src/mongo/scripting/mozjs/oid.cpp
+++ b/src/mongo/scripting/mozjs/oid.cpp
@@ -41,8 +41,10 @@
namespace mongo {
namespace mozjs {
-const JSFunctionSpec OIDInfo::methods[2] = {
- MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toString, OIDInfo), JS_FS_END,
+const JSFunctionSpec OIDInfo::methods[3] = {
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toString, OIDInfo),
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD_NO_PROTO(toJSON, OIDInfo),
+ JS_FS_END,
};
const char* const OIDInfo::className = "ObjectId";
@@ -63,6 +65,12 @@ void OIDInfo::Functions::toString::call(JSContext* cx, JS::CallArgs args) {
ValueReader(cx, args.rval()).fromStringData(str);
}
+void OIDInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ auto oid = static_cast<OID*>(JS_GetPrivate(args.thisv().toObjectOrNull()));
+
+ ValueReader(cx, args.rval()).fromBSON(BSON("$oid" << oid->toString()), nullptr, false);
+}
+
void OIDInfo::Functions::getter::call(JSContext* cx, JS::CallArgs args) {
auto oid = static_cast<OID*>(JS_GetPrivate(args.thisv().toObjectOrNull()));
diff --git a/src/mongo/scripting/mozjs/oid.h b/src/mongo/scripting/mozjs/oid.h
index 3d723b97003..06a54b740bf 100644
--- a/src/mongo/scripting/mozjs/oid.h
+++ b/src/mongo/scripting/mozjs/oid.h
@@ -45,9 +45,10 @@ struct OIDInfo : public BaseInfo {
struct Functions {
MONGO_DECLARE_JS_FUNCTION(getter);
MONGO_DECLARE_JS_FUNCTION(toString);
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
};
- static const JSFunctionSpec methods[2];
+ static const JSFunctionSpec methods[3];
static const unsigned classFlags = JSCLASS_HAS_PRIVATE;
diff --git a/src/mongo/scripting/mozjs/regexp.cpp b/src/mongo/scripting/mozjs/regexp.cpp
index b935a9fb354..55761dc606d 100644
--- a/src/mongo/scripting/mozjs/regexp.cpp
+++ b/src/mongo/scripting/mozjs/regexp.cpp
@@ -29,11 +29,27 @@
#include "mongo/platform/basic.h"
#include "mongo/scripting/mozjs/regexp.h"
+#include "mongo/scripting/mozjs/valuereader.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
namespace mongo {
namespace mozjs {
+const JSFunctionSpec RegExpInfo::methods[2] = {
+ MONGO_ATTACH_JS_FUNCTION(toJSON), JS_FS_END,
+};
+
const char* const RegExpInfo::className = "RegExp";
+void RegExpInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ ObjectWrapper o(cx, args.thisv());
+
+ auto regex_string = o.getString(InternedString::source);
+ auto flags_string = o.getString(InternedString::flags);
+
+ ValueReader(cx, args.rval())
+ .fromBSON(BSON("$regex" << regex_string << "$options" << flags_string), nullptr, false);
+}
+
} // namespace mozjs
} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/regexp.h b/src/mongo/scripting/mozjs/regexp.h
index b8553518127..33e11ef4a14 100644
--- a/src/mongo/scripting/mozjs/regexp.h
+++ b/src/mongo/scripting/mozjs/regexp.h
@@ -36,10 +36,17 @@ namespace mozjs {
/**
* The "RegExp" Javascript object.
*
- * Note that this installs over native. We only use this to grab the regexp
- * prototype early in case users overwrite it.
+ * Note that this installs "overNative", so we don't actually do anything other
+ * than layer our own toJSON function on top of the existing prototype.
*/
struct RegExpInfo : public BaseInfo {
+
+ struct Functions {
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
+ };
+
+ static const JSFunctionSpec methods[2];
+
static const char* const className;
static const InstallType installType = InstallType::OverNative;
diff --git a/src/mongo/scripting/mozjs/timestamp.cpp b/src/mongo/scripting/mozjs/timestamp.cpp
index 99d83f7c343..468c2f4927f 100644
--- a/src/mongo/scripting/mozjs/timestamp.cpp
+++ b/src/mongo/scripting/mozjs/timestamp.cpp
@@ -38,11 +38,16 @@
#include "mongo/scripting/mozjs/objectwrapper.h"
#include "mongo/scripting/mozjs/valuereader.h"
#include "mongo/scripting/mozjs/valuewriter.h"
+#include "mongo/scripting/mozjs/wrapconstrainedmethod.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
namespace mozjs {
+const JSFunctionSpec TimestampInfo::methods[2] = {
+ MONGO_ATTACH_JS_CONSTRAINED_METHOD(toJSON, TimestampInfo), JS_FS_END,
+};
+
const char* const TimestampInfo::className = "Timestamp";
namespace {
@@ -84,5 +89,15 @@ void TimestampInfo::construct(JSContext* cx, JS::CallArgs args) {
args.rval().setObjectOrNull(thisv);
}
+void TimestampInfo::Functions::toJSON::call(JSContext* cx, JS::CallArgs args) {
+ ObjectWrapper o(cx, args.thisv());
+
+ ValueReader(cx, args.rval())
+ .fromBSON(BSON("$timestamp" << BSON("t" << o.getNumber(InternedString::t) << "i"
+ << o.getNumber(InternedString::i))),
+ nullptr,
+ false);
+}
+
} // namespace mozjs
} // namespace mongo
diff --git a/src/mongo/scripting/mozjs/timestamp.h b/src/mongo/scripting/mozjs/timestamp.h
index 1dc4a998420..c5cbd869b7b 100644
--- a/src/mongo/scripting/mozjs/timestamp.h
+++ b/src/mongo/scripting/mozjs/timestamp.h
@@ -46,6 +46,12 @@ namespace mozjs {
struct TimestampInfo : public BaseInfo {
static void construct(JSContext* cx, JS::CallArgs args);
+ struct Functions {
+ MONGO_DECLARE_JS_FUNCTION(toJSON);
+ };
+
+ static const JSFunctionSpec methods[2];
+
static const char* const className;
};
diff --git a/src/mongo/scripting/mozjs/wraptype.h b/src/mongo/scripting/mozjs/wraptype.h
index d6fb135da44..76af28efd1c 100644
--- a/src/mongo/scripting/mozjs/wraptype.h
+++ b/src/mongo/scripting/mozjs/wraptype.h
@@ -226,6 +226,7 @@ public:
WrapType(JSContext* context)
: _context(context),
_proto(),
+ _constructor(),
_jsclass({T::className,
T::classFlags,
T::addProperty != BaseInfo::addProperty ? smUtils::addProperty<T> : nullptr,
@@ -265,6 +266,7 @@ public:
~WrapType() {
// Persistent globals don't RAII, you have to reset() them manually
_proto.reset();
+ _constructor.reset();
}
void install(JS::HandleObject global) {
@@ -310,7 +312,8 @@ public:
void newInstance(const JS::HandleValueArray& args, JS::MutableHandleObject out) {
dassert(T::installType == InstallType::OverNative || T::construct != BaseInfo::construct);
- out.set(_assertPtr(JS_New(_context, _proto, args)));
+ out.set(_assertPtr(JS_New(
+ _context, T::installType == InstallType::OverNative ? _constructor : _proto, args)));
}
void newInstance(JS::MutableHandleValue out) {
@@ -324,7 +327,8 @@ public:
void newInstance(const JS::HandleValueArray& args, JS::MutableHandleValue out) {
dassert(T::installType == InstallType::OverNative || T::construct != BaseInfo::construct);
- out.setObjectOrNull(_assertPtr(JS_New(_context, _proto, args)));
+ out.setObjectOrNull(_assertPtr(JS_New(
+ _context, T::installType == InstallType::OverNative ? _constructor : _proto, args)));
}
// instanceOf doesn't go up the prototype tree. It's a lower level more specific match
@@ -419,7 +423,25 @@ private:
if (!value.isObject())
uasserted(ErrorCodes::BadValue, "className isn't object");
- _proto.init(_context, value.toObjectOrNull());
+ JS::RootedObject classNameObject(_context);
+ if (!JS_ValueToObject(_context, value, &classNameObject))
+ throwCurrentJSException(_context,
+ ErrorCodes::JSInterpreterFailure,
+ "Couldn't convert className property into an object.");
+
+ JS::RootedValue protoValue(_context);
+ if (!JS_GetPropertyById(_context,
+ classNameObject,
+ InternedStringId(_context, InternedString::prototype),
+ &protoValue))
+ throwCurrentJSException(
+ _context, ErrorCodes::JSInterpreterFailure, "Couldn't get className prototype");
+
+ if (!protoValue.isObject())
+ uasserted(ErrorCodes::BadValue, "className's prototype isn't object");
+
+ _constructor.init(_context, value.toObjectOrNull());
+ _proto.init(_context, protoValue.toObjectOrNull());
_installFunctions(_proto, T::methods);
_installFunctions(global, T::freeFunctions);
@@ -508,6 +530,7 @@ private:
JSContext* _context;
JS::PersistentRootedObject _proto;
+ JS::PersistentRootedObject _constructor;
JSClass _jsclass;
};
diff --git a/src/mongo/scripting/utils.cpp b/src/mongo/scripting/utils.cpp
index 10d8fcfe020..91bd67a5e0f 100644
--- a/src/mongo/scripting/utils.cpp
+++ b/src/mongo/scripting/utils.cpp
@@ -26,6 +26,7 @@
* then also delete it in the license file.
*/
+#include "mongo/bson/json.h"
#include "mongo/scripting/engine.h"
#include "mongo/util/md5.hpp"
@@ -57,6 +58,20 @@ static BSONObj native_sleep(const mongo::BSONObj& args, void* data) {
return b.obj();
}
+static BSONObj native_tostrictjson(const mongo::BSONObj& args, void* data) {
+ uassert(40275,
+ "tostrictjson takes a single BSON object argument, and on optional boolean argument "
+ "for prettyPrint -- tostrictjson(obj, prettyPrint = false)",
+ args.nFields() >= 1 && args.firstElement().isABSONObj() &&
+ (args.nFields() == 1 || (args.nFields() == 2 && args["1"].isBoolean())));
+
+ bool prettyPrint = false;
+ if (args.nFields() == 2) {
+ prettyPrint = args["1"].boolean();
+ }
+ return BSON("" << tojson(args.firstElement().embeddedObject(), Strict, prettyPrint));
+}
+
// ---------------------------------
// ---- installer --------
// ---------------------------------
@@ -64,6 +79,7 @@ static BSONObj native_sleep(const mongo::BSONObj& args, void* data) {
void installGlobalUtils(Scope& scope) {
scope.injectNative("hex_md5", native_hex_md5);
scope.injectNative("sleep", native_sleep);
+ scope.injectNative("tostrictjson", native_tostrictjson);
}
} // namespace mongo