@@ -62,6 +62,7 @@ RequestLoader::RequestLoader(RequestOptions&& requestOptions, const SchemaLoader
6262
6363 collectVariables ();
6464
65+ // Variables can reference both input types and enums.
6566 for (const auto & variable : _variables)
6667 {
6768 collectInputTypes (variable.type );
@@ -71,6 +72,7 @@ RequestLoader::RequestLoader(RequestOptions&& requestOptions, const SchemaLoader
7172 // Handle nested input types by fully declaring the dependencies first.
7273 reorderInputTypeDependencies ();
7374
75+ // The response can also reference enums.
7476 for (const auto & responseField : _responseType.fields )
7577 {
7678 collectEnums (responseField);
@@ -604,6 +606,48 @@ void RequestLoader::validateRequest() const
604606 }
605607}
606608
609+ std::pair<RequestSchemaType, TypeModifierStack> RequestLoader::unwrapSchemaType (
610+ RequestSchemaType&& type) noexcept
611+ {
612+ std::pair<RequestSchemaType, TypeModifierStack> result { std::move (type), {} };
613+ bool wrapped = true ;
614+ bool nonNull = false ;
615+
616+ while (wrapped)
617+ {
618+ switch (result.first ->kind ())
619+ {
620+ case introspection::TypeKind::NON_NULL:
621+ nonNull = true ;
622+ result.first = result.first ->ofType ().lock ();
623+ break ;
624+
625+ case introspection::TypeKind::LIST:
626+ if (!nonNull)
627+ {
628+ result.second .push_back (service::TypeModifier::Nullable);
629+ }
630+
631+ nonNull = false ;
632+ result.second .push_back (service::TypeModifier::List);
633+ result.first = result.first ->ofType ().lock ();
634+ break ;
635+
636+ default :
637+ if (!nonNull)
638+ {
639+ result.second .push_back (service::TypeModifier::Nullable);
640+ }
641+
642+ nonNull = false ;
643+ wrapped = false ;
644+ break ;
645+ }
646+ }
647+
648+ return result;
649+ }
650+
607651std::string_view RequestLoader::trimWhitespace (std::string_view content) noexcept
608652{
609653 const auto isSpacePredicate = [](char ch) noexcept {
@@ -764,16 +808,36 @@ void RequestLoader::collectVariables() noexcept
764808
765809void RequestLoader::collectInputTypes (const RequestSchemaType& variableType) noexcept
766810{
767- // Input types may be referenced in any variable or field of a variable input type.
768- if (variableType->kind () == introspection::TypeKind::INPUT_OBJECT
769- && _inputTypeNames.emplace (variableType->name ()).second )
811+ switch (variableType->kind ())
770812 {
771- _referencedInputTypes.push_back (variableType);
813+ case introspection::TypeKind::INPUT_OBJECT:
814+ {
815+ if (_inputTypeNames.emplace (variableType->name ()).second )
816+ {
817+ _referencedInputTypes.push_back (variableType);
818+
819+ // Input types can reference other input types and enums.
820+ for (const auto & inputField : variableType->inputFields ())
821+ {
822+ const auto fieldType = inputField->type ().lock ();
823+
824+ collectInputTypes (fieldType);
825+ collectEnums (fieldType);
826+ }
827+ }
772828
773- for (const auto & inputField : variableType->inputFields ())
829+ break ;
830+ }
831+
832+ case introspection::TypeKind::LIST:
833+ case introspection::TypeKind::NON_NULL:
774834 {
775- collectInputTypes (inputField->type ().lock ());
835+ collectInputTypes (variableType->ofType ().lock ());
836+ break ;
776837 }
838+
839+ default :
840+ break ;
777841 }
778842}
779843
@@ -859,11 +923,27 @@ void RequestLoader::reorderInputTypeDependencies() noexcept
859923
860924void RequestLoader::collectEnums (const RequestSchemaType& variableType) noexcept
861925{
862- // Enums may be referenced in any variable input type or in the response itself.
863- if (variableType->kind () == introspection::TypeKind::ENUM
864- && _enumNames.emplace (variableType->name ()).second )
926+ switch (variableType->kind ())
865927 {
866- _referencedEnums.push_back (variableType);
928+ case introspection::TypeKind::ENUM:
929+ {
930+ if (_enumNames.emplace (variableType->name ()).second )
931+ {
932+ _referencedEnums.push_back (variableType);
933+ }
934+
935+ break ;
936+ }
937+
938+ case introspection::TypeKind::LIST:
939+ case introspection::TypeKind::NON_NULL:
940+ {
941+ collectEnums (variableType->ofType ().lock ());
942+ break ;
943+ }
944+
945+ default :
946+ break ;
867947 }
868948}
869949
@@ -1023,40 +1103,8 @@ void RequestLoader::SelectionVisitor::visitField(const peg::ast_node& field)
10231103 responseField.type = (*itr)->type ().lock ();
10241104 }
10251105
1026- bool wrapped = true ;
1027- bool nonNull = false ;
1028-
1029- while (wrapped)
1030- {
1031- switch (responseField.type ->kind ())
1032- {
1033- case introspection::TypeKind::NON_NULL:
1034- nonNull = true ;
1035- responseField.type = responseField.type ->ofType ().lock ();
1036- break ;
1037-
1038- case introspection::TypeKind::LIST:
1039- if (!nonNull)
1040- {
1041- responseField.modifiers .push_back (service::TypeModifier::Nullable);
1042- }
1043-
1044- nonNull = false ;
1045- responseField.modifiers .push_back (service::TypeModifier::List);
1046- responseField.type = responseField.type ->ofType ().lock ();
1047- break ;
1048-
1049- default :
1050- if (!nonNull)
1051- {
1052- responseField.modifiers .push_back (service::TypeModifier::Nullable);
1053- }
1054-
1055- nonNull = false ;
1056- wrapped = false ;
1057- break ;
1058- }
1059- }
1106+ std::tie (responseField.type , responseField.modifiers ) =
1107+ unwrapSchemaType (std::move (responseField.type ));
10601108
10611109 const peg::ast_node* selection = nullptr ;
10621110
0 commit comments