@@ -68,6 +68,9 @@ RequestLoader::RequestLoader(RequestOptions&& requestOptions, const SchemaLoader
6868 collectEnums (variable.type );
6969 }
7070
71+ // Handle nested input types by fully declaring the dependencies first.
72+ reorderInputTypeDependencies ();
73+
7174 for (const auto & responseField : _responseType.fields )
7275 {
7376 collectEnums (responseField);
@@ -774,6 +777,86 @@ void RequestLoader::collectInputTypes(const RequestSchemaType& variableType) noe
774777 }
775778}
776779
780+ void RequestLoader::reorderInputTypeDependencies () noexcept
781+ {
782+ if (_referencedInputTypes.empty ())
783+ {
784+ return ;
785+ }
786+
787+ // Build the dependency list for each input type.
788+ struct InputTypeDependencies
789+ {
790+ RequestSchemaType type;
791+ std::string_view name;
792+ std::unordered_set<std::string_view> dependencies;
793+ };
794+
795+ std::vector<InputTypeDependencies> inputTypes (_referencedInputTypes.size ());
796+
797+ std::transform (_referencedInputTypes.cbegin (),
798+ _referencedInputTypes.cend (),
799+ inputTypes.begin (),
800+ [](const RequestSchemaType& type) noexcept {
801+ InputTypeDependencies result { type, type->name () };
802+ const auto & fields = type->inputFields ();
803+
804+ std::for_each (fields.begin (),
805+ fields.end (),
806+ [&result](const std::shared_ptr<const schema::InputValue>& field) noexcept {
807+ const auto fieldType = field->type ().lock ();
808+
809+ if (fieldType->kind () == introspection::TypeKind::INPUT_OBJECT)
810+ {
811+ result.dependencies .insert (fieldType->name ());
812+ }
813+ });
814+
815+ return result;
816+ });
817+
818+ std::unordered_set<std::string_view> handled;
819+ auto itr = inputTypes.begin ();
820+
821+ while (itr != inputTypes.end ())
822+ {
823+ // Put all of the input types without unhandled dependencies at the front.
824+ const auto itrDependent = std::stable_partition (itr,
825+ inputTypes.end (),
826+ [&handled](const InputTypeDependencies& entry) noexcept {
827+ return std::find_if (entry.dependencies .cbegin (),
828+ entry.dependencies .cend (),
829+ [&handled](std::string_view dependency) noexcept {
830+ return handled.find (dependency) == handled.cend ();
831+ })
832+ == entry.dependencies .cend ();
833+ });
834+
835+ if (itrDependent != inputTypes.end ())
836+ {
837+ std::for_each (itr,
838+ itrDependent,
839+ [&handled](const InputTypeDependencies& entry) noexcept {
840+ handled.insert (entry.name );
841+ });
842+ }
843+
844+ itr = itrDependent;
845+ }
846+
847+ if (!handled.empty ())
848+ {
849+ std::transform (inputTypes.begin (),
850+ inputTypes.end (),
851+ _referencedInputTypes.begin (),
852+ [](InputTypeDependencies& entry) noexcept {
853+ auto result = std::move (entry.type );
854+
855+ return result;
856+ });
857+ }
858+ }
859+
777860void RequestLoader::collectEnums (const RequestSchemaType& variableType) noexcept
778861{
779862 // Enums may be referenced in any variable input type or in the response itself.
@@ -816,7 +899,8 @@ void RequestLoader::collectEnums(const ResponseField& responseField) noexcept
816899 {
817900 if (responseField.children )
818901 {
819- for (const auto & responseType : std::get<ResponseUnionOptions>(*responseField.children ))
902+ for (const auto & responseType :
903+ std::get<ResponseUnionOptions>(*responseField.children ))
820904 {
821905 for (const auto & field : responseType.fields )
822906 {
0 commit comments