diff options
-rw-r--r-- | buildscripts/idl/idl/binder.py | 2 | ||||
-rw-r--r-- | buildscripts/idl/idl/bson.py | 2 | ||||
-rw-r--r-- | buildscripts/idl/idl/cpp_types.py | 32 | ||||
-rw-r--r-- | buildscripts/idl/idl/generator.py | 2 | ||||
-rw-r--r-- | src/mongo/idl/basic_types.idl | 11 | ||||
-rw-r--r-- | src/mongo/idl/idl_test.cpp | 68 | ||||
-rw-r--r-- | src/mongo/idl/unittest.idl | 5 |
7 files changed, 73 insertions, 49 deletions
diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index 2f1917a6f06..ab50d0bcc35 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -201,7 +201,7 @@ def _validate_type_properties(ctxt, idl_type, syntax_type): ctxt.add_missing_ast_required_field_error(idl_type, syntax_type, idl_type.name, "deserializer") - elif not bson_type in ["object", "bindata"]: + elif not bson_type in ["array", "object", "bindata"]: if idl_type.deserializer is None: ctxt.add_missing_ast_required_field_error(idl_type, syntax_type, idl_type.name, "deserializer") diff --git a/buildscripts/idl/idl/bson.py b/buildscripts/idl/idl/bson.py index 3d1e004dbc0..3f8e5190f9d 100644 --- a/buildscripts/idl/idl/bson.py +++ b/buildscripts/idl/idl/bson.py @@ -40,7 +40,7 @@ _BSON_TYPE_INFORMATION = { "double": {'scalar': True, 'bson_type_enum': 'NumberDouble'}, "string": {'scalar': True, 'bson_type_enum': 'String'}, "object": {'scalar': False, 'bson_type_enum': 'Object'}, - # TODO: add support: "array" : { 'scalar' : False, 'bson_type_enum' : 'Array'}, + "array": {'scalar': False, 'bson_type_enum': 'Array'}, "bindata": {'scalar': True, 'bson_type_enum': 'BinData'}, "undefined": {'scalar': True, 'bson_type_enum': 'Undefined'}, "objectid": {'scalar': True, 'bson_type_enum': 'jstOID'}, diff --git a/buildscripts/idl/idl/cpp_types.py b/buildscripts/idl/idl/cpp_types.py index bb7ec7d0a22..8971d5715c8 100644 --- a/buildscripts/idl/idl/cpp_types.py +++ b/buildscripts/idl/idl/cpp_types.py @@ -652,6 +652,34 @@ class _ObjectBsonCppTypeBase(BsonCppTypeBase): return "localObject" +class _ArrayBsonCppTypeBase(BsonCppTypeBase): + """Custom C++ support for array BSON types.""" + + def gen_deserializer_expression(self, indented_writer, object_instance): + # type: (writer.IndentedTextWriter, str) -> str + if self._ast_type.deserializer: + indented_writer.write_line( + common.template_args('BSONArray localArray(${object_instance}.Obj());', + object_instance=object_instance)) + return "localArray" + + # Just pass the BSONObj through without trying to parse it. + return common.template_args('BSONArray(${object_instance}.Obj())', + object_instance=object_instance) + + def has_serializer(self): + # type: () -> bool + return self._ast_type.serializer is not None + + def gen_serializer_expression(self, indented_writer, expression): + # type: (writer.IndentedTextWriter, str) -> str + method_name = writer.get_method_name(self._ast_type.serializer) + indented_writer.write_line( + common.template_args('BSONArray localArray(${expression}.${method_name}());', + expression=expression, method_name=method_name)) + return "localArray" + + class _BinDataBsonCppTypeBase(BsonCppTypeBase): """Custom C++ support for all binData BSON types.""" @@ -690,6 +718,7 @@ class _BinDataBsonCppTypeBase(BsonCppTypeBase): def get_bson_cpp_type(ast_type): # type: (ast.Type) -> Optional[BsonCppTypeBase] """Get a class that provides custom serialization for the given BSON type.""" + # pylint: disable=too-many-return-statements # Does not support list of types if len(ast_type.bson_serialization_type) > 1: @@ -701,6 +730,9 @@ def get_bson_cpp_type(ast_type): if ast_type.bson_serialization_type[0] == 'object': return _ObjectBsonCppTypeBase(ast_type) + if ast_type.bson_serialization_type[0] == 'array': + return _ArrayBsonCppTypeBase(ast_type) + if ast_type.bson_serialization_type[0] == 'bindata': return _BinDataBsonCppTypeBase(ast_type) diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index a20f64bbcd8..51569af4d4f 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -1206,7 +1206,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): method_name=method_name, expression=expression) # BSONObjects are allowed to be pass through without deserialization - assert ast_type.bson_serialization_type == ['object'] + assert ast_type.bson_serialization_type in [['object'], ['array']] return expression # Call a static class method with the signature: diff --git a/src/mongo/idl/basic_types.idl b/src/mongo/idl/basic_types.idl index 37a7f86a0d0..c0037bbb446 100644 --- a/src/mongo/idl/basic_types.idl +++ b/src/mongo/idl/basic_types.idl @@ -187,6 +187,17 @@ types: cpp_type: "mongo::BSONObj" deserializer: "BSONObj::getOwned" + array: + bson_serialization_type: array + description: "An unowned BSONArray without custom deserialization or seialization" + cpp_type: "mongo::BSONArray" + + array_owned: + bson_serialization_type: array + description: "An owned BSONArray" + cpp_type: "mongo::BSONArray" + deserializer: "BSONObj::getOwned" + date: bson_serialization_type: date description: "A BSON UTC DateTime" diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp index b09aa091a71..daab2d425ee 100644 --- a/src/mongo/idl/idl_test.cpp +++ b/src/mongo/idl/idl_test.cpp @@ -152,17 +152,21 @@ void assert_same_types() { template <typename ParserT, typename TestT, BSONType Test_bson_type> void TestLoopback(TestT test_value) { - IDLParserErrorContext ctxt("root"); - auto testDoc = BSON("value" << test_value); - auto element = testDoc.firstElement(); ASSERT_EQUALS(element.type(), Test_bson_type); - auto testStruct = ParserT::parse(ctxt, testDoc); + auto testStruct = ParserT::parse({"test"}, testDoc); assert_same_types<decltype(testStruct.getValue()), TestT>(); - ASSERT_EQUALS(testStruct.getValue(), test_value); + // We need to use a different unittest macro for comparing obj/array. + constexpr bool isObjectTest = std::is_same_v<TestT, const BSONObj&>; + constexpr bool isArrayTest = std::is_same_v<TestT, const BSONArray&>; + if constexpr (isObjectTest || isArrayTest) { + ASSERT_BSONOBJ_EQ(testStruct.getValue(), test_value); + } else { + ASSERT_EQUALS(testStruct.getValue(), test_value); + } // Positive: Test we can roundtrip from the just parsed document { @@ -192,7 +196,15 @@ void TestLoopback(TestT test_value) { // Validate the operator == works // Use ASSERT instead of ASSERT_EQ to avoid operator<< - ASSERT(one_new == testStruct); + if constexpr (!isArrayTest) { + // BSONArray comparison not currently implemented. + ASSERT_TRUE(one_new == testStruct); + } + + if constexpr (isObjectTest) { + // Only One_plain_object implements comparison ops + ASSERT_FALSE(one_new < testStruct); + } } } @@ -207,46 +219,10 @@ TEST(IDLOneTypeTests, TestLoopbackTest) { TestLoopback<One_objectid, const OID&, jstOID>(OID::max()); TestLoopback<One_date, const Date_t&, Date>(Date_t::now()); TestLoopback<One_timestamp, const Timestamp&, bsonTimestamp>(Timestamp::max()); -} - -// Test a BSONObj can be passed through an IDL type -TEST(IDLOneTypeTests, TestObjectLoopbackTest) { - IDLParserErrorContext ctxt("root"); - - auto testValue = BSON("Hello" - << "World"); - auto testDoc = BSON("value" << testValue); - - auto element = testDoc.firstElement(); - ASSERT_EQUALS(element.type(), Object); - - auto testStruct = One_plain_object::parse(ctxt, testDoc); - assert_same_types<decltype(testStruct.getValue()), const BSONObj&>(); - - ASSERT_BSONOBJ_EQ(testStruct.getValue(), testValue); - - // 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_plain_object one_new; - one_new.setValue(testValue); - one_new.serialize(&builder); - - auto serializedDoc = builder.obj(); - ASSERT_BSONOBJ_EQ(testDoc, serializedDoc); - - ASSERT_TRUE(one_new == testStruct); - ASSERT_FALSE(one_new < testStruct); - } + TestLoopback<One_plain_object, const BSONObj&, Object>(BSON("Hello" + << "World")); + TestLoopback<One_plain_array, const BSONArray&, Array>(BSON_ARRAY("Hello" + << "World")); } // Test we compare an object with optional BSONObjs correctly diff --git a/src/mongo/idl/unittest.idl b/src/mongo/idl/unittest.idl index da3741f21cc..712a04ce4c2 100644 --- a/src/mongo/idl/unittest.idl +++ b/src/mongo/idl/unittest.idl @@ -126,6 +126,11 @@ structs: fields: value: object + one_plain_array: + description: UnitTest for a single BSONArray + fields: + value: array + one_plain_optional_object: description: UnitTest for optional BSONObj generate_comparison_operators: true |