diff options
author | Davis Haupt <davis.haupt@mongodb.com> | 2023-04-18 13:37:47 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-04-18 14:49:46 +0000 |
commit | e6d81d58334a2a15be92de7ea65cb0ae61c62e35 (patch) | |
tree | fab91413e0e72fecf228cca2ea5cde81c1bba6cb /buildscripts | |
parent | 518f98088c22598a12b33aa3457253d9fdcea0cc (diff) | |
download | mongo-e6d81d58334a2a15be92de7ea65cb0ae61c62e35.tar.gz |
SERVER-75138 Add shapification for DocumentSources which use IDL for serialization
Diffstat (limited to 'buildscripts')
-rw-r--r-- | buildscripts/idl/idl/ast.py | 7 | ||||
-rw-r--r-- | buildscripts/idl/idl/binder.py | 18 | ||||
-rw-r--r-- | buildscripts/idl/idl/errors.py | 10 | ||||
-rw-r--r-- | buildscripts/idl/idl/generator.py | 8 | ||||
-rw-r--r-- | buildscripts/idl/idl/parser.py | 2 | ||||
-rw-r--r-- | buildscripts/idl/idl/syntax.py | 2 | ||||
-rw-r--r-- | buildscripts/idl/tests/test_binder.py | 46 |
7 files changed, 66 insertions, 27 deletions
diff --git a/buildscripts/idl/idl/ast.py b/buildscripts/idl/idl/ast.py index a07d547248e..a3808963213 100644 --- a/buildscripts/idl/idl/ast.py +++ b/buildscripts/idl/idl/ast.py @@ -109,6 +109,9 @@ class Type(common.SourceLocation): self.first_element_field_name = None # type: str self.deserialize_with_tenant = False # type: bool self.internal_only = False # type: bool + # Marks whether this type is a query shape component. + # Can only be true if is_struct is true. + self.is_query_shape_component = False # type: bool super(Type, self).__init__(file_name, line, column) @@ -251,14 +254,14 @@ class Field(common.SourceLocation): # See WRITING-13831 for details on query shape. self.query_shape_literal = None # type: Optional[bool] # Determines whether or not this field represents a fieldpath that should be anonymized. - self.query_shape_fieldpath = None # type: Optional[bool] + self.query_shape_anonymize = None # type: Optional[bool] super(Field, self).__init__(file_name, line, column) @property def should_serialize_query_shape(self): # type: () -> bool - return self.query_shape_fieldpath or self.query_shape_literal + return self.query_shape_anonymize or self.query_shape_literal class Privilege(common.SourceLocation): diff --git a/buildscripts/idl/idl/binder.py b/buildscripts/idl/idl/binder.py index da4191d83fc..179768e6df1 100644 --- a/buildscripts/idl/idl/binder.py +++ b/buildscripts/idl/idl/binder.py @@ -327,17 +327,17 @@ def _bind_struct_common(ctxt, parsed_spec, struct, ast_struct): # Verify that each field on the struct defines a query shape type on the field if and only if # query_shape_component is defined on the struct. - defined_query_shape_type = ast_field.query_shape_literal is not None or ast_field.query_shape_fieldpath is not None + defined_query_shape_type = ast_field.query_shape_literal is not None or ast_field.query_shape_anonymize is not None if not field.hidden and struct.query_shape_component and not defined_query_shape_type: ctxt.add_must_declare_shape_type(ast_field, ast_struct.name, ast_field.name) if not struct.query_shape_component and defined_query_shape_type: ctxt.add_must_be_query_shape_component(ast_field, ast_struct.name, ast_field.name) - if ast_field.query_shape_fieldpath and ast_field.type.cpp_type not in [ + if ast_field.query_shape_anonymize and ast_field.type.cpp_type not in [ "std::string", "std::vector<std::string>" ]: - ctxt.add_query_shape_fieldpath_must_be_string(ast_field, ast_field.name, + ctxt.add_query_shape_anonymize_must_be_string(ast_field, ast_field.name, ast_field.type.cpp_type) # Fill out the field comparison_order property as needed @@ -455,6 +455,7 @@ def _bind_struct_type(struct): ast_type.cpp_type = _get_struct_qualified_cpp_name(struct) ast_type.bson_serialization_type = ["object"] ast_type.first_element_field_name = struct.fields[0].name if struct.fields else None + ast_type.is_query_shape_component = struct.query_shape_component return ast_type @@ -1019,6 +1020,7 @@ def _bind_type(idltype): ast_type.deserializer = _normalize_method_name(idltype.cpp_type, idltype.deserializer) ast_type.deserialize_with_tenant = idltype.deserialize_with_tenant ast_type.internal_only = idltype.internal_only + ast_type.is_query_shape_component = True return ast_type @@ -1045,7 +1047,7 @@ def _bind_field(ctxt, parsed_spec, field): ast_field.always_serialize = field.always_serialize ast_field.preparse = field.preparse ast_field.query_shape_literal = field.query_shape_literal - ast_field.query_shape_fieldpath = field.query_shape_fieldpath + ast_field.query_shape_anonymize = field.query_shape_anonymize ast_field.cpp_name = field.name if field.cpp_name: @@ -1056,11 +1058,11 @@ def _bind_field(ctxt, parsed_spec, field): ctxt.add_array_not_valid_error(ast_field, "field", ast_field.name) # Validate that 'field' is not both a query shape literal and query shape fieldpath. The two are mutually exclusive. - if ast_field.query_shape_literal is not None and ast_field.query_shape_fieldpath is not None: + if ast_field.query_shape_literal is not None and ast_field.query_shape_anonymize is not None: ctxt.add_field_cannot_be_literal_and_fieldpath(ast_field, ast_field.name) - if ast_field.query_shape_fieldpath is False: - ctxt.add_field_cannot_have_query_shape_fieldpath_false(ast_field) + if ast_field.query_shape_anonymize is False: + ctxt.add_field_cannot_have_query_shape_anonymize_false(ast_field) if field.ignore: ast_field.ignore = field.ignore @@ -1134,6 +1136,8 @@ def _bind_field(ctxt, parsed_spec, field): if ast_field.validator is None: return None + if ast_field.should_serialize_query_shape and not ast_field.type.is_query_shape_component: + ctxt.add_must_be_query_shape_component(ast_field, ast_field.type.name, ast_field.name) return ast_field diff --git a/buildscripts/idl/idl/errors.py b/buildscripts/idl/idl/errors.py index e9386535ffe..5837cb11648 100644 --- a/buildscripts/idl/idl/errors.py +++ b/buildscripts/idl/idl/errors.py @@ -950,10 +950,10 @@ class ParserContext(object): def add_must_declare_shape_type(self, location, struct_name, field_name): # type: (common.SourceLocation, str, str) -> None - """Add an error about a field not specifying either query_shape_literal or query_shape_fieldpath if the struct is query_shape_component.""" + """Add an error about a field not specifying either query_shape_literal or query_shape_anonymize if the struct is query_shape_component.""" self._add_error( location, ERROR_ID_FIELD_MUST_DECLARE_SHAPE_LITERAL, - f"Field '{field_name}' must specify either 'query_shape_literal' or 'query_shape_fieldpath' since struct '{struct_name}' is a query shape component." + f"Field '{field_name}' must specify either 'query_shape_literal' or 'query_shape_anonymize' since struct '{struct_name}' is a query shape component." ) def add_must_be_query_shape_component(self, location, struct_name, field_name): @@ -963,7 +963,7 @@ class ParserContext(object): f"Field '{field_name}' cannot specify 'query_shape_literal' property since struct '{struct_name}' is not a query shape component." ) - def add_query_shape_fieldpath_must_be_string(self, location, field_name, field_type): + def add_query_shape_anonymize_must_be_string(self, location, field_name, field_type): self._add_error( location, ERROR_ID_INVALID_TYPE_FOR_SHAPIFY, f"In order for {field_name} to be marked as a query shape fieldpath, it must have a string type, not {field_type}." @@ -975,9 +975,9 @@ class ParserContext(object): f"{field_name} cannot be marked as both a query shape literal and query shape fieldpath." ) - def add_field_cannot_have_query_shape_fieldpath_false(self, location): + def add_field_cannot_have_query_shape_anonymize_false(self, location): self._add_error(location, ERROR_ID_QUERY_SHAPE_FIELDPATH_CANNOT_BE_FALSE, - "'query_shape_fieldpath' cannot be defined as false if it is set.") + "'query_shape_anonymize' cannot be defined as false if it is set.") def _assert_unique_error_messages(): diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py index b472ffe17a6..26792609546 100644 --- a/buildscripts/idl/idl/generator.py +++ b/buildscripts/idl/idl/generator.py @@ -2166,7 +2166,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(${expression}).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'builder->append(${field_name}, options.serializeFieldPathFromString(${expression}));' ) @@ -2321,7 +2321,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(${expression}).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'builder->append(${field_name}, options.serializeFieldPathFromString(${expression}));' ) @@ -2335,7 +2335,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_template( 'options.serializeLiteralValue(value).serializeForIDL(${field_name}, builder);' ) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_template( 'idl::idlSerialize(builder, ${field_name}, options.serializeFieldPathFromString(value));' ) @@ -2382,7 +2382,7 @@ class _CppSourceFileWriter(_CppFileWriterBase): self._writer.write_line( 'options.serializeLiteralValue(%s).serializeForIDL(%s, builder);' % (_access_member(field), _get_field_constant_name(field))) - elif field.query_shape_fieldpath: + elif field.query_shape_anonymize: self._writer.write_line( 'builder->append(%s, options.serializeFieldPathFromString(%s));' % (_get_field_constant_name(field), _access_member(field))) diff --git a/buildscripts/idl/idl/parser.py b/buildscripts/idl/idl/parser.py index cc4f047231e..022ad0dd3f9 100644 --- a/buildscripts/idl/idl/parser.py +++ b/buildscripts/idl/idl/parser.py @@ -408,7 +408,7 @@ def _parse_field(ctxt, name, node): _RuleDesc('bool_scalar'), "query_shape_literal": _RuleDesc('required_bool_scalar'), - "query_shape_fieldpath": + "query_shape_anonymize": _RuleDesc('required_bool_scalar'), }) diff --git a/buildscripts/idl/idl/syntax.py b/buildscripts/idl/idl/syntax.py index c8b3573294f..f161488062e 100644 --- a/buildscripts/idl/idl/syntax.py +++ b/buildscripts/idl/idl/syntax.py @@ -494,7 +494,7 @@ class Field(common.SourceLocation): self.constructed = False # type: bool self.query_shape_literal = None # type: Optional[bool] - self.query_shape_fieldpath = None # type: Optional[bool] + self.query_shape_anonymize = None # type: Optional[bool] self.hidden = False # type: bool diff --git a/buildscripts/idl/tests/test_binder.py b/buildscripts/idl/tests/test_binder.py index a891c6f15b2..c4e3c806d71 100644 --- a/buildscripts/idl/tests/test_binder.py +++ b/buildscripts/idl/tests/test_binder.py @@ -2704,7 +2704,7 @@ class TestBinder(testcase.IDLTestcase): query_shape_literal: false """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) - # Validating query_shape_fieldpath relies on std::string + # Validating query_shape_anonymize relies on std::string basic_types = textwrap.dedent(""" types: string: @@ -2731,7 +2731,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: string field2: query_shape_literal: false @@ -2746,7 +2746,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: array<string> field2: query_shape_literal: false @@ -2762,7 +2762,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: false + query_shape_anonymize: false type: string field2: query_shape_literal: false @@ -2778,7 +2778,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: bool field2: query_shape_literal: false @@ -2794,7 +2794,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true type: array<bool> field2: query_shape_literal: false @@ -2810,7 +2810,7 @@ class TestBinder(testcase.IDLTestcase): description: "" fields: field1: - query_shape_fieldpath: true + query_shape_anonymize: true query_shape_literal: true type: string field2: @@ -2818,6 +2818,38 @@ class TestBinder(testcase.IDLTestcase): type: bool """), idl.errors.ERROR_ID_CANNOT_BE_LITERAL_AND_FIELDPATH) + self.assert_bind_fail( + basic_types + textwrap.dedent(""" + structs: + StructZero: + strict: true + description: "" + fields: + field1: + query_shape_literal: true + type: string + """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) + + self.assert_bind_fail( + basic_types + textwrap.dedent(""" + structs: + StructZero: + strict: true + description: "" + fields: + field1: + type: string + struct1: + query_shape_component: true + strict: true + description: "" + fields: + field2: + type: StructZero + description: "" + query_shape_literal: true + """), idl.errors.ERROR_ID_CANNOT_DECLARE_SHAPE_LITERAL) + if __name__ == '__main__': |