[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/gitmodimo/cppgraphqlgen/main/include/SchemaLoader.h [Back]  [Original]

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#pragma once

#ifndef SCHEMALOADER_H
#define SCHEMALOADER_H

#include "GeneratorLoader.h"

#include "graphqlservice/GraphQLParse.h"
#include "graphqlservice/GraphQLService.h"

#include "graphqlservice/internal/Grammar.h"

#include 
#include 
#include 

namespace graphql::generator {

// These are the set of built-in types in GraphQL.
enum class [[nodiscard]] BuiltinType {
	Int,
	Float,
	String,
	Boolean,
	ID,
};

using BuiltinTypeMap = std::map;

// These are the C++ types we'll use for them.
using CppTypeMap = std::array;

// Keep track of the positions of each type declaration in the file.
using PositionMap = std::unordered_map;

// For all of the named types we track, we want to keep them in order in a vector but
// be able to lookup their offset quickly by name.
using TypeNameMap = std::unordered_map;

// Scalar types are opaque to the generator, it's up to the service implementation
// to handle parsing, validating, and serializing them. We just need to track which
// scalar type names have been declared so we recognize the references.
struct [[nodiscard]] ScalarType
{
	std::string_view type;
	std::string_view description;
	std::string_view specifiedByURL {};
};

using ScalarTypeList = std::vector;

// Enum types map a type name to a collection of valid string values.
struct [[nodiscard]] EnumValueType
{
	std::string_view value;
	std::string_view cppValue;
	std::string_view description;
	std::optional deprecationReason;
	std::optional position;
};

struct [[nodiscard]] EnumType
{
	std::string_view type;
	std::string_view cppType;
	std::vector values;
	std::string_view description;
};

using EnumTypeList = std::vector;

// Input types are complex types that have a set of named fields. Each field may be
// a scalar type (including lists or non-null wrappers) or another nested input type,
// but it cannot include output object types.
enum class [[nodiscard]] InputFieldType {
	Builtin,
	Scalar,
	Enum,
	Input,
};

struct [[nodiscard]] InputField
{
	std::string_view type;
	std::string_view name;
	std::string_view cppName;
	std::string_view defaultValueString;
	response::Value defaultValue;
	InputFieldType fieldType = InputFieldType::Builtin;
	TypeModifierStack modifiers;
	std::string_view description;
	std::optional position;
};

using InputFieldList = std::vector;

struct [[nodiscard]] InputType
{
	std::string_view type;
	std::string_view cppType;
	InputFieldList fields;
	std::string_view description;
	std::unordered_set dependencies {};
	std::vector declarations {};
};

using InputTypeList = std::vector;

// Directives are defined with arguments and a list of valid locations.
struct [[nodiscard]] Directive
{
	std::string_view name;
	bool isRepeatable = false;
	std::vector locations;
	InputFieldList arguments;
	std::string_view description;
};

using DirectiveList = std::vector;

// Union types map a type name to a set of potential concrete type names.
struct [[nodiscard]] UnionType
{
	std::string_view type;
	std::string_view cppType;
	std::vector options;
	std::string_view description;
};

using UnionTypeList = std::vector;

// Output types are scalar types or complex types that have a set of named fields. Each
// field may be a scalar type (including lists or non-null wrappers) or another nested
// output type, but it cannot include input object types. Each field can also take
// optional arguments which are all input types.
enum class [[nodiscard]] OutputFieldType {
	Builtin,
	Scalar,
	Enum,
	Union,
	Interface,
	Object,
};

constexpr std::string_view strGet = "get";
constexpr std::string_view strApply = "apply";

struct [[nodiscard]] OutputField
{
	std::string_view type;
	std::string_view name;
	InputFieldList arguments;
	OutputFieldType fieldType = OutputFieldType::Builtin;
	TypeModifierStack modifiers;
	std::string_view description;
	std::optional deprecationReason;
	std::optional position;
	bool interfaceField = false;
	bool inheritedField = false;
	std::string_view accessor { strGet };
};

using OutputFieldList = std::vector;

// Interface types are abstract complex output types that have a set of fields. They
// are inherited by concrete object output types which support all of the fields in
// the interface, and the concrete object matches the interface for fragment type
// conditions. The fields can include any output type.
struct [[nodiscard]] InterfaceType
{
	std::string_view type;
	std::string_view cppType;
	std::vector interfaces;
	OutputFieldList fields;
	std::string_view description;
};

using InterfaceTypeList = std::vector;

// Object types are concrete complex output types that have a set of fields. They
// may inherit multiple interfaces.
struct [[nodiscard]] ObjectType
{
	std::string_view type;
	std::string_view cppType;
	std::vector interfaces;
	std::vector unions;
	OutputFieldList fields;
	std::string_view description;
};

using ObjectTypeList = std::vector;

// The schema maps operation types to named types.
struct [[nodiscard]] OperationType
{
	std::string_view type;
	std::string_view cppType;
	std::string_view operation;
};

using OperationTypeList = std::vector;

struct [[nodiscard]] SchemaOptions
{
	const std::string schemaFilename;
	const std::string filenamePrefix;
	const std::string schemaNamespace;
	const bool isIntrospection = false;
};

class [[nodiscard]] SchemaLoader
{
public:
	// Initialize the loader with the introspection schema or a custom GraphQL schema.
	explicit SchemaLoader(SchemaOptions&& schemaOptions);

	[[nodiscard]] bool isIntrospection() const noexcept;
	[[nodiscard]] std::string_view getSchemaDescription() const noexcept;
	[[nodiscard]] std::string_view getFilenamePrefix() const noexcept;
	[[nodiscard]] std::string_view getSchemaNamespace() const noexcept;

	[[nodiscard]] static std::string_view getIntrospectionNamespace() noexcept;
	[[nodiscard]] static const BuiltinTypeMap& getBuiltinTypes() noexcept;
	[[nodiscard]] static const CppTypeMap& getBuiltinCppTypes() noexcept;
	[[nodiscard]] static std::string_view getScalarCppType() noexcept;

	[[nodiscard]] SchemaType getSchemaType(std::string_view type) const;
	[[nodiscard]] const tao::graphqlpeg::position& getTypePosition(std::string_view type) const;

	[[nodiscard]] size_t getScalarIndex(std::string_view type) const;
	[[nodiscard]] const ScalarTypeList& getScalarTypes() const noexcept;

	[[nodiscard]] size_t getEnumIndex(std::string_view type) const;
	[[nodiscard]] const EnumTypeList& getEnumTypes() const noexcept;

	[[nodiscard]] size_t getInputIndex(std::string_view type) const;
	[[nodiscard]] const InputTypeList& getInputTypes() const noexcept;

	[[nodiscard]] size_t getUnionIndex(std::string_view type) const;
	[[nodiscard]] const UnionTypeList& getUnionTypes() const noexcept;

	[[nodiscard]] size_t getInterfaceIndex(std::string_view type) const;
	[[nodiscard]] const InterfaceTypeList& getInterfaceTypes() const noexcept;

	[[nodiscard]] size_t getObjectIndex(std::string_view type) const;
	[[nodiscard]] const ObjectTypeList& getObjectTypes() const noexcept;

	[[nodiscard]] const DirectiveList& getDirectives() const noexcept;
	[[nodiscard]] const tao::graphqlpeg::position& getDirectivePosition(
		std::string_view type) const;

	[[nodiscard]] const OperationTypeList& getOperationTypes() const noexcept;

	[[nodiscard]] static std::string_view getSafeCppName(std::string_view type) noexcept;

	[[nodiscard]] std::string_view getCppType(std::string_view type) const noexcept;
	[[nodiscard]] std::string getInputCppType(const InputField& field) const noexcept;
	[[nodiscard]] std::string getOutputCppType(const OutputField& field) const noexcept;

	[[nodiscard]] static std::string getOutputCppAccessor(const OutputField& field) noexcept;
	[[nodiscard]] static std::string getOutputCppResolver(const OutputField& field) noexcept;

private:
	[[nodiscard]] static bool isExtension(const peg::ast_node& definition) noexcept;

	void visitDefinition(const peg::ast_node& definition);

	void visitSchemaDefinition(const peg::ast_node& schemaDefinition);
	void visitSchemaExtension(const peg::ast_node& schemaExtension);
	void visitScalarTypeDefinition(const peg::ast_node& scalarTypeDefinition);
	void visitScalarTypeExtension(const peg::ast_node& scalarTypeExtension);
	void visitEnumTypeDefinition(const peg::ast_node& enumTypeDefinition);
	void visitEnumTypeExtension(const peg::ast_node& enumTypeExtension);
	void visitInputObjectTypeDefinition(const peg::ast_node& inputObjectTypeDefinition);
	void visitInputObjectTypeExtension(const peg::ast_node& inputObjectTypeExtension);
	void visitUnionTypeDefinition(const peg::ast_node& unionTypeDefinition);
	void visitUnionTypeExtension(const peg::ast_node& unionTypeExtension);
	void visitInterfaceTypeDefinition(const peg::ast_node& interfaceTypeDefinition);
	void visitInterfaceTypeExtension(const peg::ast_node& interfaceTypeExtension);
	void visitObjectTypeDefinition(const peg::ast_node& objectTypeDefinition);
	void visitObjectTypeExtension(const peg::ast_node& objectTypeExtension);
	void visitDirectiveDefinition(const peg::ast_node& directiveDefinition);

	static void blockReservedName(
		std::string_view name, std::optional position = std::nullopt);
	[[nodiscard]] static OutputFieldList getOutputFields(const peg::ast_node::children_t& fields);
	[[nodiscard]] static InputFieldList getInputFields(const peg::ast_node::children_t& fields);

	void validateSchema();
	void fixupOutputFieldList(OutputFieldList& fields,
		const std::optional& interfaceFields,
		const std::optional& accessor);
	void fixupInputFieldList(InputFieldList& fields);
	void reorderInputTypeDependencies();
	void validateImplementedInterfaces() const;
	[[nodiscard]] const InterfaceType& findInterfaceType(
		std::string_view typeName, std::string_view interfaceName) const;
	void validateInterfaceFields(std::string_view typeName, std::string_view interfaceName,
		const OutputFieldList& typeFields) const;
	void validateTransitiveInterfaces(
		std::string_view typeName, const std::vector& interfaces) const;

	[[nodiscard]] static std::string getJoinedCppName(
		std::string_view prefix, std::string_view fieldName) noexcept;

	static const std::string_view s_introspectionNamespace;
	static const BuiltinTypeMap s_builtinTypes;
	static const CppTypeMap s_builtinCppTypes;
	static const std::string_view s_scalarCppType;

	const SchemaOptions _schemaOptions;
	const bool _isIntrospection;
	std::string_view _schemaDescription;
	std::string_view _schemaNamespace;
	peg::ast _ast;

	SchemaTypeMap _schemaTypes;
	PositionMap _typePositions;
	TypeNameMap _scalarNames;
	ScalarTypeList _scalarTypes;
	TypeNameMap _enumNames;
	EnumTypeList _enumTypes;
	TypeNameMap _inputNames;
	InputTypeList _inputTypes;
	TypeNameMap _unionNames;
	UnionTypeList _unionTypes;
	TypeNameMap _interfaceNames;
	InterfaceTypeList _interfaceTypes;
	TypeNameMap _objectNames;
	ObjectTypeList _objectTypes;
	DirectiveList _directives;
	PositionMap _directivePositions;
	OperationTypeList _operationTypes;
};

} // namespace graphql::generator

#endif // SCHEMALOADER_H

Web Proxy Viewer  |  New URL  |  Original Page