From 5ab83cb6e3acaf435d0d792cf8b5360eac47ce2e Mon Sep 17 00:00:00 2001 From: Mark Benvenuto Date: Fri, 12 May 2017 09:58:02 -0400 Subject: [PATCH] SERVER-29089 Add UUID to IDL basic_types.idl --- buildscripts/idl/idl/cpp_types.py | 8 +++++-- buildscripts/idl/idl/parser.py | 5 +++++ src/mongo/idl/SConscript | 1 + src/mongo/idl/basic_types.idl | 22 +++++++++++++++++-- src/mongo/idl/idl_test.cpp | 36 +++++++++++++++++++++++++++++++ src/mongo/idl/unittest.idl | 13 ----------- src/mongo/idl/unittest_import.idl | 7 +++++- src/mongo/util/uuid.h | 19 +++++++++++----- 8 files changed, 88 insertions(+), 23 deletions(-) diff --git a/buildscripts/idl/idl/cpp_types.py b/buildscripts/idl/idl/cpp_types.py index 089c8073623..c147c746f22 100644 --- a/buildscripts/idl/idl/cpp_types.py +++ b/buildscripts/idl/idl/cpp_types.py @@ -599,8 +599,12 @@ class _BinDataBsonCppTypeBase(BsonCppTypeBase): def gen_deserializer_expression(self, indented_writer, object_instance): # type: (writer.IndentedTextWriter, unicode) -> unicode - return common.template_args( - '${object_instance}._binDataVector()', object_instance=object_instance) + if self._field.bindata_subtype == 'uuid': + return common.template_args( + '${object_instance}.uuid()', object_instance=object_instance) + else: + return common.template_args( + '${object_instance}._binDataVector()', object_instance=object_instance) def has_serializer(self): # type: () -> bool diff --git a/buildscripts/idl/idl/parser.py b/buildscripts/idl/idl/parser.py index 10ce47b1479..e4ce345b908 100644 --- a/buildscripts/idl/idl/parser.py +++ b/buildscripts/idl/idl/parser.py @@ -465,6 +465,11 @@ def parse(stream, input_file_name, resolver): imports += [(parsed_doc.spec.imports, resolved_file_name, import_file_name) for import_file_name in parsed_doc.spec.imports.imports] + # Merge cpp_includes as needed + if parsed_doc.spec.globals and parsed_doc.spec.globals.cpp_includes: + root_doc.spec.globals.cpp_includes = list( + set(root_doc.spec.globals.cpp_includes + parsed_doc.spec.globals.cpp_includes)) + # Merge symbol tables together root_doc.spec.symbols.add_imported_symbol_table(ctxt, parsed_doc.spec.symbols) if ctxt.errors.has_errors(): diff --git a/src/mongo/idl/SConscript b/src/mongo/idl/SConscript index 87c5d3c2158..d7b68634932 100644 --- a/src/mongo/idl/SConscript +++ b/src/mongo/idl/SConscript @@ -24,5 +24,6 @@ env.CppUnitTest( '$BUILD_DIR/mongo/base', '$BUILD_DIR/mongo/db/namespace_string', '$BUILD_DIR/mongo/idl/idl_parser', + '$BUILD_DIR/mongo/util/uuid', ], ) diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl index 1dd9495d65e..015e4786cfe 100644 --- a/src/mongo/idl/basic_types.idl +++ b/src/mongo/idl/basic_types.idl @@ -16,7 +16,10 @@ # IDL Basic Types global: cpp_namespace: "mongo" - + cpp_includes: + - "mongo/db/namespace_string.h" + - "mongo/util/uuid.h" + types: string: bson_serialization_type: string @@ -75,6 +78,14 @@ types: cpp_type: "std::array" deserializer: "mongo::BSONElement::uuid" + uuid: + bson_serialization_type: bindata + bindata_subtype: uuid + description: "A UUID" + cpp_type: "mongo::UUID" + deserializer: "UUID" + serializer: "mongo::UUID::toCDR" + bindata_md5: bson_serialization_type: bindata bindata_subtype: md5 @@ -103,4 +114,11 @@ types: bson_serialization_type: timestamp description: "A BSON TimeStamp" cpp_type: "mongo::Timestamp" - deserializer: "mongo::BSONElement::timestamp" \ No newline at end of file + deserializer: "mongo::BSONElement::timestamp" + + namespacestring: + bson_serialization_type: string + description: "A MongoDB NamespaceString" + cpp_type: "mongo::NamespaceString" + serializer: mongo::NamespaceString::toString + deserializer: mongo::NamespaceString diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp index c255baaa321..80d5fa721f5 100644 --- a/src/mongo/idl/idl_test.cpp +++ b/src/mongo/idl/idl_test.cpp @@ -989,6 +989,7 @@ TEST(IDLBinData, TestParse) { TestBinDataParser(); TestBinDataParser(); TestBinDataParser(); + TestBinDataParser(); } // Mixed: test a type that accepts a custom bindata type @@ -1027,6 +1028,41 @@ TEST(IDLBinData, TestCustomType) { } } +// Positive: test a type that accepts a custom UUID type +TEST(IDLBinData, TestUUIDclass) { + IDLParserErrorContext ctxt("root"); + + auto uuid = UUID::gen(); + auto testDoc = BSON("value" << uuid); + + auto element = testDoc.firstElement(); + ASSERT_EQUALS(element.type(), BinData); + ASSERT_EQUALS(element.binDataType(), newUUID); + + auto testStruct = One_UUID::parse(ctxt, testDoc); + ASSERT_TRUE(testStruct.getValue() == uuid); + + // Positive: Test we can roundtrip from the just parsed document + { + BSONObjBuilder builder; + testStruct.serialize(&builder); + auto loopbackDoc = builder.obj(); + + ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc); + } + + // Positive: Test we can serialize from nothing the same document + { + BSONObjBuilder builder; + One_UUID one_new; + one_new.setValue(uuid); + one_new.serialize(&builder); + + auto serializedDoc = builder.obj(); + ASSERT_BSONOBJ_EQ(testDoc, serializedDoc); + } +} + /** * A simple class that derives from an IDL generated class */ diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl index a686f2ff2cd..4211875cca7 100644 --- a/src/mongo/idl/unittest.idl +++ b/src/mongo/idl/unittest.idl @@ -18,7 +18,6 @@ global: # Use a nested namespace simply to exercise nested namespace support for the code generator. cpp_namespace: "mongo::idl::test" cpp_includes: - - "mongo/db/namespace_string.h" - "mongo/idl/idl_test_types.h" imports: @@ -26,18 +25,6 @@ imports: - "mongo/idl/unittest_import.idl" types: -################################################################################################## -# -# Test a custom non-BSONElement deserialization and serialization methods for a string type -# -################################################################################################## - - namespacestring: - bson_serialization_type: string - description: "A MongoDB NamespaceString" - cpp_type: "mongo::NamespaceString" - serializer: mongo::NamespaceString::toString - deserializer: mongo::NamespaceString ################################################################################################## # diff --git a/src/mongo/idl/unittest_import.idl b/src/mongo/idl/unittest_import.idl index 0e9403f65d5..73e25833d67 100644 --- a/src/mongo/idl/unittest_import.idl +++ b/src/mongo/idl/unittest_import.idl @@ -91,4 +91,9 @@ structs: one_timestamp: description: UnitTest for a single timestamp fields: - value: timestamp \ No newline at end of file + value: timestamp + + one_UUID: + description: UnitTest for a single UUID + fields: + value: uuid diff --git a/src/mongo/util/uuid.h b/src/mongo/util/uuid.h index 0ad35e1fdb9..98e41c96672 100644 --- a/src/mongo/util/uuid.h +++ b/src/mongo/util/uuid.h @@ -33,6 +33,7 @@ #include +#include "mongo/base/data_range.h" #include "mongo/base/status_with.h" #include "mongo/bson/bsonelement.h" #include "mongo/bson/bsonmisc.h" @@ -47,12 +48,11 @@ namespace mongo { class UUID { using UUIDStorage = std::array; -public: - /** - * This constructor exists for IDL only. - */ - UUID() = default; + // Make the IDL generated parser a friend + friend class One_UUID; + friend class Logical_session_id; +public: /** * The number of bytes contained in a UUID. */ @@ -87,6 +87,13 @@ public: */ static bool isUUIDString(const std::string& s); + /** + * Returns a ConstDataRange view of the UUID. + */ + ConstDataRange toCDR() const { + return ConstDataRange(reinterpret_cast(_uuid.data()), _uuid.size()); + } + /** * Append to builder as BinData(4, "...") element with the given name. */ @@ -127,6 +134,8 @@ public: }; private: + UUID() = default; + UUID(const UUIDStorage& uuid) : _uuid(uuid) {} UUIDStorage _uuid; // UUID in network byte order