summaryrefslogtreecommitdiff
path: root/src/mongo/idl
diff options
context:
space:
mode:
authorHana Pearlman <hana.pearlman@mongodb.com>2021-01-05 16:17:51 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-01-18 00:14:59 +0000
commite5e660ae76806c1cb3628f70925e10287841f478 (patch)
tree4bb5355d63215d42aa7e7a615fb247f2dd89afc1 /src/mongo/idl
parentcc8671bcf846a6aeda28a5cf81aea750c2fca4bd (diff)
downloadmongo-e5e660ae76806c1cb3628f70925e10287841f478.tar.gz
SERVER-51621: Convert findAndModify output to IDL
Diffstat (limited to 'src/mongo/idl')
-rw-r--r--src/mongo/idl/basic_types.h27
-rw-r--r--src/mongo/idl/basic_types.idl8
-rw-r--r--src/mongo/idl/idl_test.cpp91
-rw-r--r--src/mongo/idl/unittest.idl32
4 files changed, 157 insertions, 1 deletions
diff --git a/src/mongo/idl/basic_types.h b/src/mongo/idl/basic_types.h
index b0647e46733..2712d2eb7c4 100644
--- a/src/mongo/idl/basic_types.h
+++ b/src/mongo/idl/basic_types.h
@@ -32,6 +32,7 @@
#include <boost/optional.hpp>
#include "mongo/base/string_data.h"
+#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/stdx/variant.h"
@@ -130,9 +131,33 @@ public:
return _element;
}
-private:
+protected:
BSONElement _element;
};
+
+/**
+ * Class to represent a BSON element with any type from IDL. Unlike IDLAnyType, here the caller
+ * does not need to ensure the backing BSON stays alive; it is handled by the class.
+ */
+class IDLAnyTypeOwned : public IDLAnyType {
+public:
+ static IDLAnyTypeOwned parseFromBSON(const BSONElement& element) {
+ return IDLAnyTypeOwned(element);
+ }
+
+ IDLAnyTypeOwned() = default;
+ IDLAnyTypeOwned(const BSONElement& element) {
+ _obj = element.wrap();
+ _element = _obj.firstElement();
+ }
+ // This constructor can be used to avoid copying the contents of 'element'.
+ IDLAnyTypeOwned(const BSONElement& element, BSONObj owningBSONObj)
+ : IDLAnyType(element), _obj(std::move(owningBSONObj)) {}
+
+private:
+ BSONObj _obj;
+};
+
class WriteConcernW {
public:
static WriteConcernW deserializeWriteConcernW(BSONElement wEl) {
diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl
index a52fc202fe2..edd724d10c8 100644
--- a/src/mongo/idl/basic_types.idl
+++ b/src/mongo/idl/basic_types.idl
@@ -221,6 +221,14 @@ types:
cpp_type: "mongo::IDLAnyType"
serializer: mongo::IDLAnyType::serializeToBSON
deserializer: mongo::IDLAnyType::parseFromBSON
+
+ IDLAnyTypeOwned:
+ bson_serialization_type: any
+ description: "Holds a BSONElement of any type. Does not require the backing BSON to stay
+ alive."
+ cpp_type: "mongo::IDLAnyTypeOwned"
+ serializer: mongo::IDLAnyTypeOwned::serializeToBSON
+ deserializer: mongo::IDLAnyTypeOwned::parseFromBSON
writeConcernW:
bson_serialization_type:
diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp
index f1b7503dd68..6ab160786ed 100644
--- a/src/mongo/idl/idl_test.cpp
+++ b/src/mongo/idl/idl_test.cpp
@@ -34,8 +34,11 @@
#include "mongo/bson/bsonmisc.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/bson/bsontypes.h"
+#include "mongo/bson/oid.h"
#include "mongo/idl/unittest_gen.h"
#include "mongo/rpc/op_msg.h"
+#include "mongo/unittest/bson_test_util.h"
#include "mongo/unittest/unittest.h"
using namespace mongo::idl::test;
@@ -800,6 +803,36 @@ TEST(IDLFieldTests, TestOptionalFields) {
}
}
+TEST(IDLFieldTests, TestAlwaysSerializeFields) {
+ IDLParserErrorContext ctxt("root");
+
+ auto testDoc = BSON("field1"
+ << "Foo"
+ << "field3" << BSON("a" << 1234));
+ auto testStruct = Always_serialize_field::parse(ctxt, testDoc);
+
+ assert_same_types<decltype(testStruct.getField1()), const boost::optional<mongo::StringData>>();
+ assert_same_types<decltype(testStruct.getField2()), const boost::optional<std::int32_t>>();
+ assert_same_types<decltype(testStruct.getField3()), const boost::optional<mongo::BSONObj>&>();
+ assert_same_types<decltype(testStruct.getField4()), const boost::optional<mongo::BSONObj>&>();
+ assert_same_types<decltype(testStruct.getField5()), const boost::optional<mongo::BSONObj>&>();
+
+ ASSERT_EQUALS("Foo", testStruct.getField1().get());
+ ASSERT_FALSE(testStruct.getField2().is_initialized());
+ ASSERT_BSONOBJ_EQ(BSON("a" << 1234), testStruct.getField3().get());
+ ASSERT_FALSE(testStruct.getField4().is_initialized());
+ ASSERT_FALSE(testStruct.getField5().is_initialized());
+
+ BSONObjBuilder builder;
+ testStruct.serialize(&builder);
+ auto loopbackDoc = builder.obj();
+ auto docWithNulls = BSON("field1"
+ << "Foo"
+ << "field2" << BSONNULL << "field3" << BSON("a" << 1234) << "field4"
+ << BSONNULL);
+ ASSERT_BSONOBJ_EQ(docWithNulls, loopbackDoc);
+}
+
template <typename TestT>
void TestWeakType(TestT test_value) {
IDLParserErrorContext ctxt("root");
@@ -3112,5 +3145,63 @@ TEST(IDLCommand, BasicNamespaceConstGetterCommand_TestNonConstGetterGeneration)
}
}
+TEST(IDLTypeCommand, TestCommandWithIDLAnyTypeOwnedField) {
+ IDLParserErrorContext ctxt("root");
+
+ auto parsed = CommandWithAnyTypeOwnedMember::parse(
+ ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName << 1 << "anyTypeField"
+ << "string literal"
+ << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), String);
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().str(), "string literal");
+
+ parsed = CommandWithAnyTypeOwnedMember::parse(ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName
+ << 1 << "anyTypeField" << 1234 << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), NumberInt);
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().numberInt(), 1234);
+
+ parsed = CommandWithAnyTypeOwnedMember::parse(ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName
+ << 1 << "anyTypeField" << 1234.5 << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), NumberDouble);
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().numberDouble(), 1234.5);
+
+ parsed = CommandWithAnyTypeOwnedMember::parse(ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName
+ << 1 << "anyTypeField" << OID::max() << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), jstOID);
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().OID(), OID::max());
+
+ parsed = CommandWithAnyTypeOwnedMember::parse(ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName
+ << 1 << "anyTypeField"
+ << BSON("a"
+ << "b")
+ << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), Object);
+ ASSERT_BSONOBJ_EQ(parsed.getAnyTypeField().getElement().Obj(),
+ BSON("a"
+ << "b"));
+
+ parsed = CommandWithAnyTypeOwnedMember::parse(ctxt,
+ BSON(CommandWithAnyTypeOwnedMember::kCommandName
+ << 1 << "anyTypeField"
+ << BSON_ARRAY("a"
+ << "b")
+ << "$db"
+ << "db"));
+ ASSERT_EQ(parsed.getAnyTypeField().getElement().type(), Array);
+ ASSERT_BSONELT_EQ(parsed.getAnyTypeField().getElement(),
+ BSON("anyTypeField" << BSON_ARRAY("a"
+ << "b"))["anyTypeField"]);
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl
index 01fad9499ee..8751e82037b 100644
--- a/src/mongo/idl/unittest.idl
+++ b/src/mongo/idl/unittest.idl
@@ -343,6 +343,30 @@ structs:
type: bindata_uuid
optional: true
+ always_serialize_field:
+ description: UnitTest for always_serialize fields
+ fields:
+ field1:
+ type: string
+ always_serialize: true
+ optional: true
+ field2:
+ type: int
+ always_serialize: true
+ optional: true
+ field3:
+ type: object
+ always_serialize: true
+ optional: true
+ field4:
+ type: object
+ always_serialize: true
+ optional: true
+ field5:
+ type: object
+ always_serialize: false
+ optional: true
+
##################################################################################################
#
# Test array of simple types
@@ -829,6 +853,14 @@ commands:
reply_type: OkReply
fields:
anyTypeField: IDLAnyType
+
+ CommandWithAnyTypeOwnedMember:
+ description: "A mock command to test IDLAnyTypeOwned"
+ command_name: CommandWithValueTypeMember
+ namespace: ignored
+ reply_type: OkReply
+ fields:
+ anyTypeField: IDLAnyTypeOwned
# Test that we correctly generate C++ base classes for versioned API commands with different
# key names, command names, and C++ names.