diff options
Diffstat (limited to 'src/mongo/idl')
-rw-r--r-- | src/mongo/idl/basic_types.h | 27 | ||||
-rw-r--r-- | src/mongo/idl/basic_types.idl | 8 | ||||
-rw-r--r-- | src/mongo/idl/idl_test.cpp | 91 | ||||
-rw-r--r-- | src/mongo/idl/unittest.idl | 32 |
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. |