@@ -41,7 +41,6 @@ RequestLoader::RequestLoader(RequestOptions&& requestOptions, const SchemaLoader
4141 validateRequest ();
4242
4343 findOperation ();
44- collectVariables ();
4544 collectFragments ();
4645
4746 const peg::ast_node* selection = nullptr ;
@@ -60,6 +59,19 @@ RequestLoader::RequestLoader(RequestOptions&& requestOptions, const SchemaLoader
6059
6160 visitor.visit (*selection);
6261 _responseType.fields = visitor.getFields ();
62+
63+ collectVariables ();
64+
65+ for (const auto & variable : _variables)
66+ {
67+ collectInputTypes (variable.type );
68+ collectEnums (variable.type );
69+ }
70+
71+ for (const auto & responseField : _responseType.fields )
72+ {
73+ collectEnums (responseField);
74+ }
6375}
6476
6577std::string_view RequestLoader::getRequestFilename () const noexcept
@@ -99,14 +111,63 @@ std::string_view RequestLoader::getRequestText() const noexcept
99111 return trimWhitespace (_requestText);
100112}
101113
114+ const ResponseType& RequestLoader::getResponseType () const noexcept
115+ {
116+ return _responseType;
117+ }
118+
102119const RequestVariableList& RequestLoader::getVariables () const noexcept
103120{
104121 return _variables;
105122}
106123
107- const ResponseType & RequestLoader::getResponseType () const noexcept
124+ const RequestSchemaTypeList & RequestLoader::getReferencedInputTypes () const noexcept
108125{
109- return _responseType;
126+ return _referencedInputTypes;
127+ }
128+
129+ const RequestSchemaTypeList& RequestLoader::getReferencedEnums () const noexcept
130+ {
131+ return _referencedEnums;
132+ }
133+
134+ std::string RequestLoader::getInputCppType (const RequestVariable& variable) const noexcept
135+ {
136+ size_t templateCount = 0 ;
137+ std::ostringstream inputType;
138+
139+ for (auto modifier : variable.modifiers )
140+ {
141+ switch (modifier)
142+ {
143+ case service::TypeModifier::Nullable:
144+ inputType << R"cpp( std::optional<)cpp" ;
145+ ++templateCount;
146+ break ;
147+
148+ case service::TypeModifier::List:
149+ inputType << R"cpp( std::vector<)cpp" ;
150+ ++templateCount;
151+ break ;
152+
153+ default :
154+ break ;
155+ }
156+ }
157+
158+ inputType << getCppType (field.type );
159+
160+ for (size_t i = 0 ; i < templateCount; ++i)
161+ {
162+ inputType << R"cpp( >)cpp" ;
163+ }
164+
165+ return inputType.str ();
166+ }
167+
168+ std::string RequestLoader::getOutputCppType (const ResponseField& field) const noexcept
169+ {
170+
110171}
111172
112173void RequestLoader::buildSchema ()
@@ -411,10 +472,10 @@ void RequestLoader::addTypesToSchema()
411472 }
412473}
413474
414- std::shared_ptr< const schema::BaseType> RequestLoader::getSchemaType (
475+ RequestSchemaType RequestLoader::getSchemaType (
415476 std::string_view type, const TypeModifierStack& modifiers) const noexcept
416477{
417- std::shared_ptr< const schema::BaseType> introspectionType = _schema->LookupType (type);
478+ RequestSchemaType introspectionType = _schema->LookupType (type);
418479
419480 if (introspectionType)
420481 {
@@ -577,6 +638,13 @@ void RequestLoader::findOperation()
577638 _operationName.empty () ? _responseType.type ->name () : _operationName);
578639}
579640
641+ void RequestLoader::collectFragments () noexcept
642+ {
643+ peg::for_each_child<peg::fragment_definition>(*_ast.root , [this ](const peg::ast_node& child) {
644+ _fragments.emplace (child.children .front ()->string_view (), &child);
645+ });
646+ }
647+
580648void RequestLoader::collectVariables () noexcept
581649{
582650 peg::for_each_child<peg::variable>(*_operation,
@@ -635,16 +703,80 @@ void RequestLoader::collectVariables() noexcept
635703 });
636704}
637705
638- void RequestLoader::collectFragments ( ) noexcept
706+ void RequestLoader::collectInputTypes ( const RequestSchemaType& variableType ) noexcept
639707{
640- peg::for_each_child<peg::fragment_definition>(*_ast.root , [this ](const peg::ast_node& child) {
641- _fragments.emplace (child.children .front ()->string_view (), &child);
642- });
708+ // Input types may be referenced in any variable or field of a variable input type.
709+ if (variableType->kind () == introspection::TypeKind::INPUT_OBJECT
710+ && _inputTypeNames.emplace (variableType->name ()).second )
711+ {
712+ _referencedInputTypes.push_back (variableType);
713+
714+ for (const auto & inputField : variableType->inputFields ())
715+ {
716+ collectInputTypes (inputField->type ().lock ());
717+ }
718+ }
719+ }
720+
721+ void RequestLoader::collectEnums (const RequestSchemaType& variableType) noexcept
722+ {
723+ // Enums may be referenced in any variable input type or in the response itself.
724+ if (variableType->kind () == introspection::TypeKind::ENUM
725+ && _enumNames.emplace (variableType->name ()).second )
726+ {
727+ _referencedEnums.push_back (variableType);
728+ }
729+ }
730+
731+ void RequestLoader::collectEnums (const ResponseField& responseField) noexcept
732+ {
733+ switch (responseField.type ->kind ())
734+ {
735+ case introspection::TypeKind::ENUM:
736+ {
737+ if (_enumNames.emplace (responseField.type ->name ()).second )
738+ {
739+ _referencedEnums.push_back (responseField.type );
740+ }
741+
742+ break ;
743+ }
744+
745+ case introspection::TypeKind::OBJECT:
746+ case introspection::TypeKind::INTERFACE:
747+ {
748+ if (responseField.children )
749+ {
750+ for (const auto & field : std::get<ResponseFieldList>(*responseField.children ))
751+ {
752+ collectEnums (field);
753+ }
754+ }
755+
756+ break ;
757+ }
758+
759+ case introspection::TypeKind::UNION:
760+ {
761+ if (responseField.children )
762+ {
763+ for (const auto & responseType : std::get<ResponseUnionOptions>(*responseField.children ))
764+ {
765+ for (const auto & field : responseType.fields )
766+ {
767+ collectEnums (field);
768+ }
769+ }
770+ }
771+
772+ break ;
773+ }
774+ }
643775}
644776
645777RequestLoader::SelectionVisitor::SelectionVisitor (const SchemaLoader& schemaLoader,
646778 const FragmentDefinitionMap& fragments, const std::shared_ptr<schema::Schema>& schema,
647- const std::shared_ptr< const schema::BaseType> & type)
779+ const RequestSchemaType & type)
648780 : _schemaLoader(schemaLoader)
649781 , _fragments(fragments)
650782 , _schema(schema)
@@ -742,6 +874,12 @@ void RequestLoader::SelectionVisitor::visitField(const peg::ast_node& field)
742874 return typeField->name () == name;
743875 });
744876
877+ if (itr == typeFields.end ())
878+ {
879+ // Skip fields that are not found on the current type.
880+ return ;
881+ }
882+
745883 responseField.type = (*itr)->type ().lock ();
746884 }
747885
@@ -869,20 +1007,55 @@ void RequestLoader::SelectionVisitor::visitFragmentSpread(const peg::ast_node& f
8691007 };
8701008 }
8711009
872- for (const auto & selection : itr->second ->children )
873- {
874- visit (*selection);
875- }
1010+ const auto typeCondition = itr->second ->children [1 ].get ();
1011+ const auto fragmentType = _schema->LookupType (typeCondition->children .front ()->string_view ());
1012+ const auto & selection = *(itr->second ->children .back ());
1013+ SelectionVisitor selectionVisitor { _schemaLoader, _fragments, _schema, fragmentType };
1014+
1015+ selectionVisitor.visit (selection);
1016+ mergeFragmentFields (selectionVisitor.getFields ());
8761017}
8771018
8781019void RequestLoader::SelectionVisitor::visitInlineFragment (const peg::ast_node& inlineFragment)
8791020{
880- peg::on_first_child<peg::selection_set>(inlineFragment, [this ](const peg::ast_node& child) {
881- for (const auto & selection : child.children )
1021+ const peg::ast_node* typeCondition = nullptr ;
1022+
1023+ peg::on_first_child<peg::type_condition>(inlineFragment,
1024+ [&typeCondition](const peg::ast_node& child) {
1025+ typeCondition = &child;
1026+ });
1027+
1028+ peg::on_first_child<peg::selection_set>(inlineFragment,
1029+ [this , typeCondition](const peg::ast_node& child) {
1030+ const auto fragmentType = typeCondition
1031+ ? _schema->LookupType (typeCondition->children .front ()->string_view ())
1032+ : _type;
1033+ const auto & selection = child;
1034+ SelectionVisitor selectionVisitor { _schemaLoader, _fragments, _schema, fragmentType };
1035+
1036+ selectionVisitor.visit (selection);
1037+ mergeFragmentFields (selectionVisitor.getFields ());
1038+ });
1039+ }
1040+
1041+ void RequestLoader::SelectionVisitor::mergeFragmentFields (
1042+ ResponseFieldList&& fragmentFields) noexcept
1043+ {
1044+ fragmentFields.erase (std::remove_if (fragmentFields.begin (),
1045+ fragmentFields.end (),
1046+ [this ](const ResponseField& fragmentField) noexcept {
1047+ return !_names.emplace (fragmentField.name ).second ;
1048+ }),
1049+ fragmentFields.cend ());
1050+
1051+ if (!fragmentFields.empty ())
1052+ {
1053+ _fields.reserve (_fields.size () + fragmentFields.size ());
1054+ for (auto & fragmentField : fragmentFields)
8821055 {
883- visit (*selection );
1056+ _fields. push_back ( std::move (fragmentField) );
8841057 }
885- });
1058+ }
8861059}
8871060
8881061} /* namespace graphql::generator */
0 commit comments