// 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