summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-06-19 14:22:19 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-06-19 17:17:49 -0400
commit6b311efc1742cdb94381cc929c85ce8e5480b218 (patch)
treefcb2db2d87081f0c11b142079436b5aeec595d46
parent1babec6a705c242628a765935ac9d98b56a41218 (diff)
downloadmongo-6b311efc1742cdb94381cc929c85ce8e5480b218.tar.gz
SERVER-29715 IDL generator for commands with required namespace should generate a constructor
-rw-r--r--buildscripts/idl/idl/generator.py47
-rw-r--r--buildscripts/idl/idl/struct_types.py68
-rw-r--r--src/mongo/idl/idl_test.cpp6
3 files changed, 74 insertions, 47 deletions
diff --git a/buildscripts/idl/idl/generator.py b/buildscripts/idl/idl/generator.py
index 673f351e11c..5ac49cda708 100644
--- a/buildscripts/idl/idl/generator.py
+++ b/buildscripts/idl/idl/generator.py
@@ -332,6 +332,14 @@ class _CppHeaderFileWriter(_CppFileWriterBase):
return writer.IndentedScopedBlock(self._writer,
'class %s {' % common.title_case(class_name), '};')
+ def gen_class_constructors(self, struct):
+ # type: (ast.Struct) -> None
+ """Generate the declarations for the class constructors."""
+ struct_type_info = struct_types.get_struct_info(struct)
+
+ if struct_type_info.get_constructor_method():
+ self._writer.write_line(struct_type_info.get_constructor_method().get_declaration())
+
def gen_serializer_methods(self, struct):
# type: (ast.Struct) -> None
"""Generate a serializer method declarations."""
@@ -529,6 +537,10 @@ class _CppHeaderFileWriter(_CppFileWriterBase):
self.write_empty_line()
# Write constructor
+ self.gen_class_constructors(struct)
+ self.write_empty_line()
+
+ # Write serialization
self.gen_serializer_methods(struct)
if isinstance(struct, ast.Command):
@@ -693,16 +705,15 @@ class _CppSourceFileWriter(_CppFileWriterBase):
object_value = self._gen_field_deserializer_expression('element', field)
self._writer.write_line('%s = %s;' % (_get_field_member_name(field), object_value))
- def gen_command_namespace_check(self, command):
- # type: (ast.Command) -> None
- """Generate a namespace check for a command."""
-
- with self._predicate("firstFieldFound == false"):
- struct_type_info = struct_types.get_struct_info(command)
- struct_type_info.gen_namespace_check(self._writer)
+ def gen_constructors(self, struct):
+ # type: (ast.Struct) -> None
+ """Generate the C++ constructor definitions."""
- self._writer.write_line('firstFieldFound = true;')
- self._writer.write_line('continue;')
+ struct_type_info = struct_types.get_struct_info(struct)
+ if struct_type_info.get_constructor_method():
+ with self._block('%s : _nss(nss) {' %
+ (struct_type_info.get_constructor_method().get_definition()), '}'):
+ self._writer.write_line('// Used for initialization only')
def gen_deserializer_methods(self, struct):
# type: (ast.Struct) -> None
@@ -713,7 +724,13 @@ class _CppSourceFileWriter(_CppFileWriterBase):
with self._block('%s {' %
(struct_type_info.get_deserializer_static_method().get_definition()), '}'):
- self._writer.write_line('%s object;' % common.title_case(struct.name))
+ if isinstance(struct, ast.Command) and struct_type_info.get_constructor_method():
+ self._writer.write_line('%s object(%s);' % (
+ common.title_case(struct.name),
+ 'ctxt.parseNSCollectionRequired(dbName, bsonObject.firstElement())'))
+ else:
+ self._writer.write_line('%s object;' % common.title_case(struct.name))
+
self._writer.write_line(struct_type_info.get_deserializer_method().get_call('object'))
self._writer.write_line('return object;')
@@ -731,8 +748,12 @@ class _CppSourceFileWriter(_CppFileWriterBase):
self._writer.write_line('const auto fieldName = element.fieldNameStringData();')
self._writer.write_empty_line()
+ # For commands, we need to skip over the first field
if isinstance(struct, ast.Command):
- self.gen_command_namespace_check(struct)
+ with self._predicate("firstFieldFound == false"):
+ self._writer.write_line('firstFieldFound = true;')
+ self._writer.write_line('continue;')
+ self._writer.write_empty_line()
field_usage_check.add_store()
self._writer.write_empty_line()
@@ -988,6 +1009,10 @@ class _CppSourceFileWriter(_CppFileWriterBase):
self.gen_string_constants_definitions(struct)
self.write_empty_line()
+ # Write constructor
+ self.gen_constructors(struct)
+ self.write_empty_line()
+
# Write deserializer
self.gen_deserializer_methods(struct)
self.write_empty_line()
diff --git a/buildscripts/idl/idl/struct_types.py b/buildscripts/idl/idl/struct_types.py
index 1a92b1ed4f8..82ec208d65c 100644
--- a/buildscripts/idl/idl/struct_types.py
+++ b/buildscripts/idl/idl/struct_types.py
@@ -27,7 +27,7 @@ from . import writer
class MethodInfo(object):
"""Class that encapslates information about a method and how to declare, define, and call it."""
- def __init__(self, class_name, method_name, args, return_type, static=False, const=False):
+ def __init__(self, class_name, method_name, args, return_type=None, static=False, const=False):
# type: (unicode, unicode, List[unicode], unicode, bool, bool) -> None
# pylint: disable=too-many-arguments
"""Create a MethodInfo instance."""
@@ -43,16 +43,21 @@ class MethodInfo(object):
"""Get a declaration for a method."""
pre_modifiers = ''
post_modifiers = ''
+ return_type_str = ''
+
if self._static:
pre_modifiers = 'static '
if self._const:
post_modifiers = ' const'
+ if self._return_type:
+ return_type_str = self._return_type + ' '
+
return common.template_args(
- "${pre_modifiers}${return_type} ${method_name}(${args})${post_modifiers};",
+ "${pre_modifiers}${return_type}${method_name}(${args})${post_modifiers};",
pre_modifiers=pre_modifiers,
- return_type=self._return_type,
+ return_type=return_type_str,
method_name=self._method_name,
args=', '.join(self._args),
post_modifiers=post_modifiers)
@@ -62,14 +67,18 @@ class MethodInfo(object):
"""Get a definition for a method."""
pre_modifiers = ''
post_modifiers = ''
+ return_type_str = ''
if self._const:
post_modifiers = ' const'
+ if self._return_type:
+ return_type_str = self._return_type + ' '
+
return common.template_args(
- "${pre_modifiers}${return_type} ${class_name}::${method_name}(${args})${post_modifiers}",
+ "${pre_modifiers}${return_type}${class_name}::${method_name}(${args})${post_modifiers}",
pre_modifiers=pre_modifiers,
- return_type=self._return_type,
+ return_type=return_type_str,
class_name=self._class_name,
method_name=self._method_name,
args=', '.join(self._args),
@@ -98,6 +107,12 @@ class StructTypeInfoBase(object):
__metaclass__ = ABCMeta
@abstractmethod
+ def get_constructor_method(self):
+ # type: () -> MethodInfo
+ """Get the constructor method for a struct."""
+ pass
+
+ @abstractmethod
def get_serializer_method(self):
# type: () -> MethodInfo
"""Get the serializer method for a struct."""
@@ -139,12 +154,6 @@ class StructTypeInfoBase(object):
"""Serialize the first field of a Command."""
pass
- @abstractmethod
- def gen_namespace_check(self, indented_writer):
- # type: (writer.IndentedTextWriter) -> None
- """Generate the namespace check predicate for a command."""
- pass
-
class _StructTypeInfo(StructTypeInfoBase):
"""Class for struct code generation."""
@@ -154,6 +163,10 @@ class _StructTypeInfo(StructTypeInfoBase):
"""Create a _StructTypeInfo instance."""
self._struct = struct
+ def get_constructor_method(self):
+ # type: () -> MethodInfo
+ pass
+
def get_serializer_method(self):
# type: () -> MethodInfo
return MethodInfo(
@@ -193,10 +206,6 @@ class _StructTypeInfo(StructTypeInfoBase):
# type: (writer.IndentedTextWriter) -> None
pass
- def gen_namespace_check(self, indented_writer):
- # type: (writer.IndentedTextWriter) -> None
- pass
-
class _IgnoredCommandTypeInfo(_StructTypeInfo):
"""Class for command code generation."""
@@ -236,10 +245,6 @@ class _IgnoredCommandTypeInfo(_StructTypeInfo):
# type: (writer.IndentedTextWriter) -> None
indented_writer.write_line('builder->append("%s", 1);' % (self._command.name))
- def gen_namespace_check(self, indented_writer):
- # type: (writer.IndentedTextWriter) -> None
- pass
-
class _CommandWithNamespaceTypeInfo(_StructTypeInfo):
"""Class for command code generation."""
@@ -251,23 +256,24 @@ class _CommandWithNamespaceTypeInfo(_StructTypeInfo):
super(_CommandWithNamespaceTypeInfo, self).__init__(command)
+ def get_constructor_method(self):
+ # type: () -> MethodInfo
+ class_name = common.title_case(self._struct.name)
+ return MethodInfo(class_name, class_name, ['const NamespaceString& nss'])
+
def get_serializer_method(self):
# type: () -> MethodInfo
# Commands that require namespaces require it as a parameter to serialize()
return MethodInfo(
common.title_case(self._struct.name),
- 'serialize', ['const NamespaceString& ns', 'BSONObjBuilder* builder'],
+ 'serialize', ['BSONObjBuilder* builder'],
'void',
const=True)
def get_to_bson_method(self):
# type: () -> MethodInfo
# Commands that require namespaces require it as a parameter to serialize()
- return MethodInfo(
- common.title_case(self._struct.name),
- 'toBSON', ['const NamespaceString& ns'],
- 'BSONObj',
- const=True)
+ return MethodInfo(common.title_case(self._struct.name), 'toBSON', [], 'BSONObj', const=True)
def get_deserializer_static_method(self):
# type: () -> MethodInfo
@@ -290,20 +296,16 @@ class _CommandWithNamespaceTypeInfo(_StructTypeInfo):
def gen_getter_method(self, indented_writer):
# type: (writer.IndentedTextWriter) -> None
- indented_writer.write_line('const NamespaceString& getNamespace() const { return _ns; }')
+ indented_writer.write_line('const NamespaceString& getNamespace() const { return _nss; }')
def gen_member(self, indented_writer):
# type: (writer.IndentedTextWriter) -> None
- indented_writer.write_line('NamespaceString _ns;')
+ indented_writer.write_line('NamespaceString _nss;')
def gen_serializer(self, indented_writer):
# type: (writer.IndentedTextWriter) -> None
- indented_writer.write_line('builder->append("%s", ns.toString());' % (self._command.name))
-
- def gen_namespace_check(self, indented_writer):
- # type: (writer.IndentedTextWriter) -> None
- # TODO: should the name of the first element be validated??
- indented_writer.write_line('_ns = ctxt.parseNSCollectionRequired(dbName, element);')
+ indented_writer.write_line('builder->append("%s", _nss.coll());' % (self._command.name))
+ indented_writer.write_empty_line()
def get_struct_info(struct):
diff --git a/src/mongo/idl/idl_test.cpp b/src/mongo/idl/idl_test.cpp
index 024121041ae..f97fddd6577 100644
--- a/src/mongo/idl/idl_test.cpp
+++ b/src/mongo/idl/idl_test.cpp
@@ -1455,7 +1455,7 @@ TEST(IDLCommand, TestConcatentateWithDb) {
// Positive: Test we can roundtrip from the just parsed document
{
BSONObjBuilder builder;
- testStruct.serialize(NamespaceString("coll1"), &builder);
+ testStruct.serialize(&builder);
auto loopbackDoc = builder.obj();
ASSERT_BSONOBJ_EQ(testDoc, loopbackDoc);
@@ -1464,10 +1464,10 @@ TEST(IDLCommand, TestConcatentateWithDb) {
// Positive: Test we can serialize from nothing the same document
{
BSONObjBuilder builder;
- BasicConcatenateWithDbCommand one_new;
+ BasicConcatenateWithDbCommand one_new(NamespaceString("db.coll1"));
one_new.setField1(3);
one_new.setField2("five");
- one_new.serialize(NamespaceString("coll1"), &builder);
+ one_new.serialize(&builder);
auto serializedDoc = builder.obj();
ASSERT_BSONOBJ_EQ(testDoc, serializedDoc);