summaryrefslogtreecommitdiff
path: root/buildscripts
diff options
context:
space:
mode:
authorDavis Haupt <davis.haupt@mongodb.com>2023-04-18 13:37:47 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-04-18 14:49:46 +0000
commite6d81d58334a2a15be92de7ea65cb0ae61c62e35 (patch)
treefab91413e0e72fecf228cca2ea5cde81c1bba6cb /buildscripts
parent518f98088c22598a12b33aa3457253d9fdcea0cc (diff)
downloadmongo-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.py7
-rw-r--r--buildscripts/idl/idl/binder.py18
-rw-r--r--buildscripts/idl/idl/errors.py10
-rw-r--r--buildscripts/idl/idl/generator.py8
-rw-r--r--buildscripts/idl/idl/parser.py2
-rw-r--r--buildscripts/idl/idl/syntax.py2
-rw-r--r--buildscripts/idl/tests/test_binder.py46
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__':