// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. #pragma once #ifndef REQUESTLOADER_H #define REQUESTLOADER_H #include "GeneratorLoader.h" #include "graphqlservice/GraphQLParse.h" #include "graphqlservice/GraphQLService.h" #include "graphqlservice/internal/Grammar.h" #include "graphqlservice/internal/Schema.h" #include namespace graphql::generator { using RequestSchemaType = std::shared_ptr; using RequestSchemaTypeList = std::vector; struct ResponseField; using ResponseFieldList = std::vector; struct [[nodiscard]] ResponseType { RequestSchemaType type; std::string_view cppType; ResponseFieldList fields; }; struct [[nodiscard]] ResponseField { RequestSchemaType type; TypeModifierStack modifiers; std::string_view name; std::string_view cppName; std::optional position; ResponseFieldList children; }; struct [[nodiscard]] RequestInputType { RequestSchemaType type; std::unordered_set dependencies {}; std::vector declarations {}; }; using RequestInputTypeList = std::vector; struct [[nodiscard]] RequestVariable { RequestInputType inputType; TypeModifierStack modifiers; std::string_view name; std::string_view cppName; std::string_view defaultValueString; response::Value defaultValue; std::optional position; }; using RequestVariableList = std::vector; struct [[nodiscard]] Operation { const peg::ast_node* operation; std::string_view name; std::string_view type; ResponseType responseType {}; RequestVariableList variables {}; internal::string_view_set inputTypeNames {}; RequestInputTypeList referencedInputTypes {}; internal::string_view_set enumNames {}; RequestSchemaTypeList referencedEnums {}; }; using OperationList = std::vector; struct [[nodiscard]] RequestOptions { const std::string requestFilename; const std::optional operationName; const bool noIntrospection = false; }; class SchemaLoader; class [[nodiscard]] RequestLoader { public: explicit RequestLoader(RequestOptions&& requestOptions, const SchemaLoader& schemaLoader); [[nodiscard]] std::string_view getRequestFilename() const noexcept; [[nodiscard]] const OperationList& getOperations() const noexcept; [[nodiscard]] std::string_view getOperationDisplayName( const Operation& operation) const noexcept; [[nodiscard]] std::string getOperationNamespace(const Operation& operation) const noexcept; [[nodiscard]] std::string_view getOperationType(const Operation& operation) const noexcept; [[nodiscard]] std::string_view getRequestText() const noexcept; [[nodiscard]] const ResponseType& getResponseType(const Operation& operation) const noexcept; [[nodiscard]] const RequestVariableList& getVariables( const Operation& operation) const noexcept; [[nodiscard]] const RequestInputTypeList& getReferencedInputTypes( const Operation& operation) const noexcept; [[nodiscard]] const RequestSchemaTypeList& getReferencedEnums( const Operation& operation) const noexcept; [[nodiscard]] std::string getInputCppType( const RequestSchemaType& wrappedInputType) const noexcept; [[nodiscard]] std::string getInputCppType( const RequestSchemaType& inputType, const TypeModifierStack& modifiers) const noexcept; [[nodiscard]] static std::string getOutputCppType( std::string_view outputCppType, const TypeModifierStack& modifiers) noexcept; [[nodiscard]] static std::pair unwrapSchemaType( RequestSchemaType&& type) noexcept; private: void buildSchema(); void addTypesToSchema(); [[nodiscard]] RequestSchemaType getSchemaType( std::string_view type, const TypeModifierStack& modifiers) const noexcept; void validateRequest() const; [[nodiscard]] static std::string_view trimWhitespace(std::string_view content) noexcept; void findOperation(); void collectFragments() noexcept; void collectVariables(Operation& operation) noexcept; void collectInputTypes(Operation& operation, const RequestSchemaType& variableType) noexcept; void reorderInputTypeDependencies(Operation& operation); void collectEnums(Operation& operation, const RequestSchemaType& variableType) noexcept; void collectEnums(Operation& operation, const ResponseField& responseField) noexcept; using FragmentDefinitionMap = std::map; // SelectionVisitor visits the AST and fills in the ResponseType for the request. class [[nodiscard]] SelectionVisitor { public: explicit SelectionVisitor(const SchemaLoader& schemaLoader, const FragmentDefinitionMap& fragments, const std::shared_ptr& schema, const RequestSchemaType& type); void visit(const peg::ast_node& selection); [[nodiscard]] ResponseFieldList getFields(); private: void visitField(const peg::ast_node& field); void visitFragmentSpread(const peg::ast_node& fragmentSpread); void visitInlineFragment(const peg::ast_node& inlineFragment); void mergeFragmentFields(ResponseFieldList&& fragmentFields) noexcept; const SchemaLoader& _schemaLoader; const FragmentDefinitionMap& _fragments; const std::shared_ptr& _schema; const RequestSchemaType& _type; internal::string_view_set _names; ResponseFieldList _fields; }; const RequestOptions _requestOptions; const SchemaLoader& _schemaLoader; std::shared_ptr _schema; peg::ast _ast; std::string _requestText; OperationList _operations; FragmentDefinitionMap _fragments; }; } // namespace graphql::generator #endif // REQUESTLOADER_H