diff --git a/.gitignore b/.gitignore index d67ed041..a3a04514 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ Debug/ Release/ Testing/ Win32/ -/include/graphqlservice/IntrospectionSchema.h +/include/graphqlservice/introspection/IntrospectionSchema.h /IntrospectionSchema.cpp *.filters *.vcxproj @@ -27,12 +27,16 @@ Makefile .ninja_* schemagen settings.json +/samples/benchmark +/samples/benchmark_nointrospection /samples/sample +/samples/sample_nointrospection /src/cmake/ /test/argument_tests /test/pegtl_tests /test/response_tests /test/today_tests +/test/nointrospection_tests build/ install/ isenseconfig/ diff --git a/doc/subscriptions.md b/doc/subscriptions.md index 05323694..0b4702f9 100644 --- a/doc/subscriptions.md +++ b/doc/subscriptions.md @@ -83,8 +83,8 @@ tell which operation type it is without parsing the query and searching for a specific operation name, so it's hard to tell whether you should call `resolve` or `subscribe` when the request is received that way. To help with that, there's a public `Request::findOperationDefinition` method which returns -the operation type as a `std::string` along with a pointer to the AST node for +the operation type as a `std::string_view` along with a pointer to the AST node for the selected operation in the parsed query: ```cpp -std::pair findOperationDefinition(const peg::ast_node& root, const std::string& operationName) const; +std::pair findOperationDefinition(peg::ast& root, std::string_view operationName) const; ``` \ No newline at end of file diff --git a/include/SchemaGenerator.h b/include/SchemaGenerator.h index 02dd608d..59a36f59 100644 --- a/include/SchemaGenerator.h +++ b/include/SchemaGenerator.h @@ -237,6 +237,7 @@ struct GeneratorOptions const bool verbose = false; const bool separateFiles = false; const bool noStubs = false; + const bool noIntrospection = false; }; // RAII object to help with emitting matching include guard begin and end statements @@ -280,7 +281,7 @@ class PendingBlankLine bool reset() noexcept; private: - bool _pending = false; + bool _pending = true; std::ostream& _outputFile; }; diff --git a/include/Validation.h b/include/Validation.h index 44a9158e..ce45f8d1 100644 --- a/include/Validation.h +++ b/include/Validation.h @@ -6,12 +6,16 @@ #ifndef VALIDATION_H #define VALIDATION_H +#include "graphqlservice/GraphQLSchema.h" #include "graphqlservice/GraphQLService.h" -#include "graphqlservice/IntrospectionSchema.h" namespace graphql::service { -using ValidateType = response::Value; +using ValidateType = std::optional>; +using SharedType = std::shared_ptr; + +SharedType getSharedType(const ValidateType& type) noexcept; +ValidateType getValidateType(const SharedType& type) noexcept; struct ValidateArgument { @@ -20,7 +24,7 @@ struct ValidateArgument ValidateType type; }; -using ValidateTypeFieldArguments = std::map; +using ValidateTypeFieldArguments = std::map; struct ValidateTypeField { @@ -28,7 +32,7 @@ struct ValidateTypeField ValidateTypeFieldArguments arguments; }; -using ValidateDirectiveArguments = std::map; +using ValidateDirectiveArguments = std::map; struct ValidateDirective { @@ -40,14 +44,14 @@ struct ValidateArgumentVariable { bool operator==(const ValidateArgumentVariable& other) const; - std::string name; + std::string_view name; }; struct ValidateArgumentEnumValue { bool operator==(const ValidateArgumentEnumValue& other) const; - std::string value; + std::string_view value; }; struct ValidateArgumentValue; @@ -71,7 +75,7 @@ struct ValidateArgumentMap { bool operator==(const ValidateArgumentMap& other) const; - std::map values; + std::map values; }; using ValidateArgumentVariant = std::variant& _errors; }; -using ValidateFieldArguments = std::map; +using ValidateFieldArguments = std::map; struct ValidateField { - ValidateField(std::string&& returnType, std::optional&& objectType, - const std::string& fieldName, ValidateFieldArguments&& arguments); + ValidateField(ValidateType&& returnType, ValidateType&& objectType, std::string_view fieldName, + ValidateFieldArguments&& arguments); bool operator==(const ValidateField& other) const; - std::string returnType; - std::optional objectType; - std::string fieldName; + ValidateType returnType; + ValidateType objectType; + std::string_view fieldName; ValidateFieldArguments arguments; }; -using ValidateTypeKinds = std::map; +using ValidateTypes = std::map; // ValidateVariableTypeVisitor visits the AST and builds a ValidateType structure representing // a variable type in an operation definition as if it came from an Introspection query. class ValidateVariableTypeVisitor { public: - ValidateVariableTypeVisitor(const ValidateTypeKinds& typeKinds); + ValidateVariableTypeVisitor( + const std::shared_ptr& schema, const ValidateTypes& types); void visit(const peg::ast_node& typeName); @@ -152,7 +157,8 @@ class ValidateVariableTypeVisitor void visitListType(const peg::ast_node& listType); void visitNonNullType(const peg::ast_node& nonNullType); - const ValidateTypeKinds& _typeKinds; + const std::shared_ptr& _schema; + const ValidateTypes& _types; bool _isInputType = false; ValidateType _variableType; @@ -163,38 +169,34 @@ class ValidateVariableTypeVisitor class ValidateExecutableVisitor { public: - ValidateExecutableVisitor(const Request& service); + ValidateExecutableVisitor(const std::shared_ptr& schema); void visit(const peg::ast_node& root); std::vector getStructuredErrors(); private: - response::Value executeQuery(std::string_view query) const; - - static ValidateTypeFieldArguments getArguments(response::ListType&& argumentsMember); + static ValidateTypeFieldArguments getArguments( + const std::vector>& args); - using FieldTypes = std::map; - using TypeFields = std::map; + using FieldTypes = std::map; + using TypeFields = std::map; using InputFieldTypes = ValidateTypeFieldArguments; - using InputTypeFields = std::map; - using EnumValues = std::map>; + using InputTypeFields = std::map; + using EnumValues = std::map>; - std::optional getTypeKind(const std::string& name) const; - std::optional getScopedTypeKind() const; constexpr bool isScalarType(introspection::TypeKind kind); - bool matchesScopedType(const std::string& name) const; + bool matchesScopedType(std::string_view name) const; TypeFields::const_iterator getScopedTypeFields(); - InputTypeFields::const_iterator getInputTypeFields(const std::string& name); + InputTypeFields::const_iterator getInputTypeFields(std::string_view name); static const ValidateType& getValidateFieldType(const FieldTypes::mapped_type& value); static const ValidateType& getValidateFieldType(const InputFieldTypes::mapped_type& value); template - static std::string getFieldType(const _FieldTypes& fields, const std::string& name); + static ValidateType getFieldType(const _FieldTypes& fields, std::string_view name); template - static std::string getWrappedFieldType(const _FieldTypes& fields, const std::string& name); - static std::string getWrappedFieldType(const ValidateType& returnType); + static ValidateType getWrappedFieldType(const _FieldTypes& fields, std::string_view name); void visitFragmentDefinition(const peg::ast_node& fragmentDefinition); void visitOperationDefinition(const peg::ast_node& operationDefinition); @@ -213,23 +215,22 @@ class ValidateExecutableVisitor bool validateVariableType(bool isNonNull, const ValidateType& variableType, const schema_location& position, const ValidateType& inputType); - const Request& _service; + const std::shared_ptr _schema; std::vector _errors; - using OperationTypes = std::map; - using Directives = std::map; - using ExecutableNodes = std::map; - using FragmentSet = std::unordered_set; - using MatchingTypes = std::map>; - using ScalarTypes = std::set; - using VariableDefinitions = std::map; - using VariableTypes = std::map; + using Directives = std::map; + using ExecutableNodes = std::map; + using FragmentSet = std::unordered_set; + using MatchingTypes = std::map>; + using ScalarTypes = std::set; + using VariableDefinitions = std::map; + using VariableTypes = std::map; using OperationVariables = std::optional; - using VariableSet = std::set; + using VariableSet = std::set; // These members store Introspection schema information which does not change between queries. - OperationTypes _operationTypes; - ValidateTypeKinds _typeKinds; + ValidateTypes _operationTypes; + ValidateTypes _types; MatchingTypes _matchingTypes; Directives _directives; EnumValues _enumValues; @@ -250,8 +251,8 @@ class ValidateExecutableVisitor size_t _fieldCount = 0; TypeFields _typeFields; InputTypeFields _inputTypeFields; - std::string _scopedType; - std::map _selectionFields; + ValidateType _scopedType; + std::map _selectionFields; }; } /* namespace graphql::service */ diff --git a/include/graphqlservice/GraphQLGrammar.h b/include/graphqlservice/GraphQLGrammar.h index c40a56f0..e255319e 100644 --- a/include/graphqlservice/GraphQLGrammar.h +++ b/include/graphqlservice/GraphQLGrammar.h @@ -34,6 +34,18 @@ void for_each_child(const ast_node& n, std::function&& fu } } +template +void on_first_child_if(const ast_node& n, std::function&& func) +{ + for (const auto& child : n.children) + { + if (child->is_type() && func(*child)) + { + return; + } + } +} + template void on_first_child(const ast_node& n, std::function&& func) { @@ -48,83 +60,66 @@ void on_first_child(const ast_node& n, std::function&& fu } // https://facebook.github.io/graphql/June2018/#sec-Source-Text -struct source_character - : sor - , utf8::range<0x0020, 0xFFFF>> +struct source_character : sor, utf8::range<0x0020, 0xFFFF>> { }; // https://facebook.github.io/graphql/June2018/#sec-Comments -struct comment - : seq, until> +struct comment : seq, until> { }; // https://facebook.github.io/graphql/June2018/#sec-Source-Text.Ignored-Tokens -struct ignored - : sor - , comment> +struct ignored : sor, comment> { }; // https://facebook.github.io/graphql/June2018/#sec-Names -struct name - : identifier +struct name : identifier { }; -struct variable_name_content - : name +struct variable_name_content : name { }; // https://facebook.github.io/graphql/June2018/#Variable -struct variable_name - : if_must, variable_name_content> +struct variable_name : if_must, variable_name_content> { }; // https://facebook.github.io/graphql/June2018/#sec-Null-Value -struct null_keyword - : TAO_PEGTL_KEYWORD("null") +struct null_keyword : TAO_PEGTL_KEYWORD("null") { }; -struct quote_token - : one<'"'> +struct quote_token : one<'"'> { }; -struct backslash_token - : one<'\\'> +struct backslash_token : one<'\\'> { }; -struct escaped_unicode_content - : rep<4, xdigit> +struct escaped_unicode_content : rep<4, xdigit> { }; // https://facebook.github.io/graphql/June2018/#EscapedUnicode -struct escaped_unicode - : if_must, escaped_unicode_content> +struct escaped_unicode : if_must, escaped_unicode_content> { }; // https://facebook.github.io/graphql/June2018/#EscapedCharacter -struct escaped_char - : one<'"', '\\', '/', 'b', 'f', 'n', 'r', 't'> +struct escaped_char : one<'"', '\\', '/', 'b', 'f', 'n', 'r', 't'> { }; -struct string_escape_sequence_content - : sor +struct string_escape_sequence_content : sor { }; -struct string_escape_sequence - : if_must +struct string_escape_sequence : if_must { }; @@ -139,18 +134,15 @@ struct string_quote_content }; // https://facebook.github.io/graphql/June2018/#StringCharacter -struct string_quote - : if_must +struct string_quote : if_must { }; -struct block_quote_token - : rep<3, quote_token> +struct block_quote_token : rep<3, quote_token> { }; -struct block_escape_sequence - : seq +struct block_escape_sequence : seq { }; @@ -165,78 +157,64 @@ struct block_quote_content }; // https://facebook.github.io/graphql/June2018/#BlockStringCharacter -struct block_quote - : if_must +struct block_quote : if_must { }; // https://facebook.github.io/graphql/June2018/#StringValue -struct string_value - : sor +struct string_value : sor { }; // https://facebook.github.io/graphql/June2018/#NonZeroDigit -struct nonzero_digit - : range<'1', '9'> +struct nonzero_digit : range<'1', '9'> { }; -struct zero_digit - : one<'0'> +struct zero_digit : one<'0'> { }; // https://facebook.github.io/graphql/June2018/#NegativeSign -struct negative_sign - : one<'-'> +struct negative_sign : one<'-'> { }; // https://facebook.github.io/graphql/June2018/#IntegerPart -struct integer_part - : seq, sor>>> +struct integer_part : seq, sor>>> { }; // https://facebook.github.io/graphql/June2018/#IntValue -struct integer_value - : integer_part +struct integer_value : integer_part { }; -struct fractional_part_content - : plus +struct fractional_part_content : plus { }; // https://facebook.github.io/graphql/June2018/#FractionalPart -struct fractional_part - : if_must, fractional_part_content> +struct fractional_part : if_must, fractional_part_content> { }; // https://facebook.github.io/graphql/June2018/#ExponentIndicator -struct exponent_indicator - : one<'e', 'E'> +struct exponent_indicator : one<'e', 'E'> { }; // https://facebook.github.io/graphql/June2018/#Sign -struct sign - : one<'+', '-'> +struct sign : one<'+', '-'> { }; -struct exponent_part_content - : seq, plus> +struct exponent_part_content : seq, plus> { }; // https://facebook.github.io/graphql/June2018/#ExponentPart -struct exponent_part - : if_must +struct exponent_part : if_must { }; @@ -246,63 +224,52 @@ struct float_value { }; -struct true_keyword - : TAO_PEGTL_KEYWORD("true") +struct true_keyword : TAO_PEGTL_KEYWORD("true") { }; -struct false_keyword - : TAO_PEGTL_KEYWORD("false") +struct false_keyword : TAO_PEGTL_KEYWORD("false") { }; // https://facebook.github.io/graphql/June2018/#BooleanValue -struct bool_value - : sor +struct bool_value : sor { }; // https://facebook.github.io/graphql/June2018/#EnumValue -struct enum_value - : seq, name> +struct enum_value : seq, name> { }; // https://facebook.github.io/graphql/June2018/#OperationType struct operation_type - : sor + : sor { }; -struct alias_name - : name +struct alias_name : name { }; // https://facebook.github.io/graphql/June2018/#Alias -struct alias - : seq, one<':'>> +struct alias : seq, one<':'>> { }; -struct argument_name - : name +struct argument_name : name { }; struct input_value; -struct argument_content - : seq, one<':'>, star, input_value> +struct argument_content : seq, one<':'>, star, input_value> { }; // https://facebook.github.io/graphql/June2018/#Argument -struct argument - : if_must +struct argument : if_must { }; @@ -312,8 +279,7 @@ struct arguments_content }; // https://facebook.github.io/graphql/June2018/#Arguments -struct arguments - : if_must, arguments_content> +struct arguments : if_must, arguments_content> { }; @@ -325,24 +291,20 @@ struct list_value_content }; // https://facebook.github.io/graphql/June2018/#ListValue -struct list_value - : if_must, list_value_content> +struct list_value : if_must, list_value_content> { }; -struct object_field_name - : name +struct object_field_name : name { }; -struct object_field_content - : seq, one<':'>, star, input_value> +struct object_field_content : seq, one<':'>, star, input_value> { }; // https://facebook.github.io/graphql/June2018/#ObjectField -struct object_field - : if_must +struct object_field : if_must { }; @@ -352,54 +314,40 @@ struct object_value_content }; // https://facebook.github.io/graphql/June2018/#ObjectValue -struct object_value - : if_must, object_value_content> +struct object_value : if_must, object_value_content> { }; -struct variable_value - : variable_name +struct variable_value : variable_name { }; struct input_value_content - : sor + : sor { }; // https://facebook.github.io/graphql/June2018/#Value -struct input_value - : must +struct input_value : must { }; -struct list_entry - : input_value_content +struct list_entry : input_value_content { }; -struct default_value_content - : seq, input_value> +struct default_value_content : seq, input_value> { }; // https://facebook.github.io/graphql/June2018/#DefaultValue -struct default_value - : if_must, default_value_content> +struct default_value : if_must, default_value_content> { }; // https://facebook.github.io/graphql/June2018/#NamedType -struct named_type - : name +struct named_type : name { }; @@ -412,25 +360,21 @@ struct list_type_content }; // https://facebook.github.io/graphql/June2018/#ListType -struct list_type - : if_must, list_type_content> +struct list_type : if_must, list_type_content> { }; // https://facebook.github.io/graphql/June2018/#NonNullType -struct nonnull_type - : seq, star, one<'!'>> +struct nonnull_type : seq, star, one<'!'>> { }; -struct type_name_content - : sor +struct type_name_content : sor { }; // https://facebook.github.io/graphql/June2018/#Type -struct type_name - : must +struct type_name : must { }; @@ -440,8 +384,7 @@ struct variable_content }; // https://facebook.github.io/graphql/June2018/#VariableDefinition -struct variable - : if_must +struct variable : if_must { }; @@ -451,115 +394,96 @@ struct variable_definitions_content }; // https://facebook.github.io/graphql/June2018/#VariableDefinitions -struct variable_definitions - : if_must, variable_definitions_content> +struct variable_definitions : if_must, variable_definitions_content> { }; -struct directive_name - : name +struct directive_name : name { }; -struct directive_content - : seq, arguments>> +struct directive_content : seq, arguments>> { }; // https://facebook.github.io/graphql/June2018/#Directive -struct directive - : if_must, directive_content> +struct directive : if_must, directive_content> { }; // https://facebook.github.io/graphql/June2018/#Directives -struct directives - : list> +struct directives : list> { }; struct selection_set; -struct field_name - : name +struct field_name : name { }; -struct field_start - : seq>, field_name> +struct field_start : seq>, field_name> { }; -struct field_arguments - : opt, arguments> +struct field_arguments : opt, arguments> { }; -struct field_directives - : seq, directives> +struct field_directives : seq, directives> { }; -struct field_selection_set - : seq, selection_set> +struct field_selection_set : seq, selection_set> { }; struct field_content - : sor, field_selection_set> - , seq - , field_arguments> + : sor, field_selection_set>, + seq, field_arguments> { }; // https://facebook.github.io/graphql/June2018/#Field -struct field - : if_must +struct field : if_must { }; -struct on_keyword - : TAO_PEGTL_KEYWORD("on") +struct on_keyword : TAO_PEGTL_KEYWORD("on") { }; // https://facebook.github.io/graphql/June2018/#FragmentName -struct fragment_name - : seq, name> +struct fragment_name : seq, name> { }; -struct fragment_token - : ellipsis +struct fragment_token : ellipsis { }; // https://facebook.github.io/graphql/June2018/#FragmentSpread -struct fragment_spread - : seq, fragment_name, opt, directives>> +struct fragment_spread : seq, fragment_name, opt, directives>> { }; -struct type_condition_content - : seq, named_type> +struct type_condition_content : seq, named_type> { }; // https://facebook.github.io/graphql/June2018/#TypeCondition -struct type_condition - : if_must +struct type_condition : if_must { }; // https://facebook.github.io/graphql/June2018/#InlineFragment struct inline_fragment - : seq, type_condition>, opt, directives>, star, selection_set> + : seq, type_condition>, opt, directives>, star, + selection_set> { }; -struct fragement_spread_or_inline_fragment_content - : sor +struct fragement_spread_or_inline_fragment_content : sor { }; @@ -569,9 +493,7 @@ struct fragement_spread_or_inline_fragment }; // https://facebook.github.io/graphql/June2018/#Selection -struct selection - : sor +struct selection : sor { }; @@ -581,91 +503,80 @@ struct selection_set_content }; // https://facebook.github.io/graphql/June2018/#SelectionSet -struct selection_set - : if_must, selection_set_content> +struct selection_set : if_must, selection_set_content> { }; -struct operation_name - : name +struct operation_name : name { }; struct operation_definition_operation_type_content - : seq, operation_name>, opt, variable_definitions>, opt, directives>, star, selection_set> + : seq, operation_name>, opt, variable_definitions>, + opt, directives>, star, selection_set> { }; // https://facebook.github.io/graphql/June2018/#OperationDefinition struct operation_definition - : sor - , selection_set> + : sor, selection_set> { }; struct fragment_definition_content - : seq, fragment_name, plus, type_condition, opt, directives>, star, selection_set> + : seq, fragment_name, plus, type_condition, + opt, directives>, star, selection_set> { }; // https://facebook.github.io/graphql/June2018/#FragmentDefinition -struct fragment_definition - : if_must +struct fragment_definition : if_must { }; // https://facebook.github.io/graphql/June2018/#ExecutableDefinition -struct executable_definition - : sor +struct executable_definition : sor { }; -struct schema_keyword - : TAO_PEGTL_KEYWORD("schema") +struct schema_keyword : TAO_PEGTL_KEYWORD("schema") { }; -struct root_operation_definition_content - : seq, one<':'>, star, named_type> +struct root_operation_definition_content : seq, one<':'>, star, named_type> { }; // https://facebook.github.io/graphql/June2018/#RootOperationTypeDefinition -struct root_operation_definition - : if_must +struct root_operation_definition : if_must { }; struct schema_definition_content - : seq, directives>, star, one<'{'>, star, list>, star, must>> + : seq, directives>, star, one<'{'>, star, + list>, star, must>> { }; // https://facebook.github.io/graphql/June2018/#SchemaDefinition -struct schema_definition - : if_must +struct schema_definition : if_must { }; -struct scalar_keyword - : TAO_PEGTL_KEYWORD("scalar") +struct scalar_keyword : TAO_PEGTL_KEYWORD("scalar") { }; // https://facebook.github.io/graphql/June2018/#Description -struct description - : string_value +struct description : string_value { }; -struct scalar_name - : name +struct scalar_name : name { }; -struct scalar_type_definition_start - : seq>, scalar_keyword> +struct scalar_type_definition_start : seq>, scalar_keyword> { }; @@ -680,15 +591,13 @@ struct scalar_type_definition { }; -struct type_keyword - : TAO_PEGTL_KEYWORD("type") +struct type_keyword : TAO_PEGTL_KEYWORD("type") { }; struct input_field_definition; -struct arguments_definition_start - : one<'('> +struct arguments_definition_start : one<'('> { }; @@ -698,24 +607,22 @@ struct arguments_definition_content }; // https://facebook.github.io/graphql/June2018/#ArgumentsDefinition -struct arguments_definition - : if_must +struct arguments_definition : if_must { }; -struct field_definition_start - : seq>, field_name> +struct field_definition_start : seq>, field_name> { }; struct field_definition_content - : seq, arguments_definition>, star, one<':'>, star, type_name, opt, directives>> + : seq, arguments_definition>, star, one<':'>, star, + type_name, opt, directives>> { }; // https://facebook.github.io/graphql/June2018/#FieldDefinition -struct field_definition - : if_must +struct field_definition : if_must { }; @@ -725,18 +632,17 @@ struct fields_definition_content }; // https://facebook.github.io/graphql/June2018/#FieldsDefinition -struct fields_definition - : if_must, fields_definition_content> +struct fields_definition : if_must, fields_definition_content> { }; -struct interface_type - : named_type +struct interface_type : named_type { }; struct implements_interfaces_content - : seq, one<'&'>>, star, list, one<'&'>, star>>> + : seq, one<'&'>>, star, + list, one<'&'>, star>>> { }; @@ -746,41 +652,36 @@ struct implements_interfaces { }; -struct object_name - : name +struct object_name : name { }; -struct object_type_definition_start - : seq>, type_keyword> +struct object_type_definition_start : seq>, type_keyword> { }; -struct object_type_definition_object_name - : seq, object_name> +struct object_type_definition_object_name : seq, object_name> { }; -struct object_type_definition_implements_interfaces - : opt, implements_interfaces> +struct object_type_definition_implements_interfaces : opt, implements_interfaces> { }; -struct object_type_definition_directives - : seq, directives> +struct object_type_definition_directives : seq, directives> { }; -struct object_type_definition_fields_definition - : seq, fields_definition> +struct object_type_definition_fields_definition : seq, fields_definition> { }; struct object_type_definition_content : seq, object_type_definition_fields_definition> - , seq - , object_type_definition_implements_interfaces>> + sor, object_type_definition_fields_definition>, + seq, + object_type_definition_implements_interfaces>> { }; @@ -790,40 +691,35 @@ struct object_type_definition { }; -struct interface_keyword - : TAO_PEGTL_KEYWORD("interface") +struct interface_keyword : TAO_PEGTL_KEYWORD("interface") { }; -struct interface_name - : name +struct interface_name : name { }; -struct interface_type_definition_start - : seq>, interface_keyword> +struct interface_type_definition_start : seq>, interface_keyword> { }; -struct interface_type_definition_interface_name - : seq, interface_name> +struct interface_type_definition_interface_name : seq, interface_name> { }; -struct interface_type_definition_directives - : opt, directives> +struct interface_type_definition_directives : opt, directives> { }; -struct interface_type_definition_fields_definition - : seq, fields_definition> +struct interface_type_definition_fields_definition : seq, fields_definition> { }; struct interface_type_definition_content : seq - , interface_type_definition_directives>> + sor, + interface_type_definition_directives>> { }; @@ -833,88 +729,75 @@ struct interface_type_definition { }; -struct union_keyword - : TAO_PEGTL_KEYWORD("union") +struct union_keyword : TAO_PEGTL_KEYWORD("union") { }; -struct union_name - : name +struct union_name : name { }; -struct union_type - : named_type +struct union_type : named_type { }; -struct union_member_types_start - : one<'='> +struct union_member_types_start : one<'='> { }; struct union_member_types_content - : seq, one<'|'>>, star, list, one<'|'>, star>>> + : seq, one<'|'>>, star, + list, one<'|'>, star>>> { }; // https://facebook.github.io/graphql/June2018/#UnionMemberTypes -struct union_member_types - : if_must +struct union_member_types : if_must { }; -struct union_type_definition_start - : seq>, union_keyword> +struct union_type_definition_start : seq>, union_keyword> { }; -struct union_type_definition_directives - : opt, directives> +struct union_type_definition_directives : opt, directives> { }; struct union_type_definition_content : seq, union_name, - sor, union_member_types>> - , union_type_definition_directives>> + sor, union_member_types>>, + union_type_definition_directives>> { }; // https://facebook.github.io/graphql/June2018/#UnionTypeDefinition -struct union_type_definition - : if_must +struct union_type_definition : if_must { }; -struct enum_keyword - : TAO_PEGTL_KEYWORD("enum") +struct enum_keyword : TAO_PEGTL_KEYWORD("enum") { }; -struct enum_name - : name +struct enum_name : name { }; -struct enum_value_definition_start - : seq>, enum_value> +struct enum_value_definition_start : seq>, enum_value> { }; -struct enum_value_definition_content - : opt, directives> +struct enum_value_definition_content : opt, directives> { }; // https://facebook.github.io/graphql/June2018/#EnumValueDefinition -struct enum_value_definition - : if_must +struct enum_value_definition : if_must { }; -struct enum_values_definition_start - : one<'{'> +struct enum_values_definition_start : one<'{'> { }; @@ -929,68 +812,58 @@ struct enum_values_definition { }; -struct enum_type_definition_start - : seq>, enum_keyword> +struct enum_type_definition_start : seq>, enum_keyword> { }; -struct enum_type_definition_name - : seq, enum_name> +struct enum_type_definition_name : seq, enum_name> { }; -struct enum_type_definition_directives - : opt, directives> +struct enum_type_definition_directives : opt, directives> { }; -struct enum_type_definition_enum_values_definition - : seq, enum_values_definition> +struct enum_type_definition_enum_values_definition : seq, enum_values_definition> { }; struct enum_type_definition_content : seq - , enum_type_definition_directives>> + sor, + enum_type_definition_directives>> { }; // https://facebook.github.io/graphql/June2018/#EnumTypeDefinition -struct enum_type_definition - : if_must +struct enum_type_definition : if_must { }; -struct input_keyword - : TAO_PEGTL_KEYWORD("input") +struct input_keyword : TAO_PEGTL_KEYWORD("input") { }; -struct input_field_definition_start - : seq>, argument_name> +struct input_field_definition_start : seq>, argument_name> { }; -struct input_field_definition_type_name - : seq, one<':'>, star, type_name> +struct input_field_definition_type_name : seq, one<':'>, star, type_name> { }; -struct input_field_definition_default_value - : opt, default_value> +struct input_field_definition_default_value : opt, default_value> { }; -struct input_field_definition_directives - : seq, directives> +struct input_field_definition_directives : seq, directives> { }; struct input_field_definition_content : seq - , input_field_definition_default_value>> + sor, + input_field_definition_default_value>> { }; @@ -1000,8 +873,7 @@ struct input_field_definition { }; -struct input_fields_definition_start - : one<'{'> +struct input_fields_definition_start : one<'{'> { }; @@ -1016,30 +888,27 @@ struct input_fields_definition { }; -struct input_object_type_definition_start - : seq>, input_keyword> +struct input_object_type_definition_start : seq>, input_keyword> { }; -struct input_object_type_definition_object_name - : seq, object_name> +struct input_object_type_definition_object_name : seq, object_name> { }; -struct input_object_type_definition_directives - : opt, directives> +struct input_object_type_definition_directives : opt, directives> { }; -struct input_object_type_definition_fields_definition - : seq, input_fields_definition> +struct input_object_type_definition_fields_definition : seq, input_fields_definition> { }; struct input_object_type_definition_content : seq - , input_object_type_definition_directives>> + sor, + input_object_type_definition_directives>> { }; @@ -1051,53 +920,39 @@ struct input_object_type_definition // https://facebook.github.io/graphql/June2018/#TypeDefinition struct type_definition - : sor + : sor { }; // https://facebook.github.io/graphql/June2018/#ExecutableDirectiveLocation struct executable_directive_location - : sor + : sor { }; // https://facebook.github.io/graphql/June2018/#TypeSystemDirectiveLocation struct type_system_directive_location - : sor + : sor { }; // https://facebook.github.io/graphql/June2018/#DirectiveLocation -struct directive_location - : sor +struct directive_location : sor { }; // https://facebook.github.io/graphql/June2018/#DirectiveLocations struct directive_locations - : seq, star>, list, one<'|'>, star>>> + : seq, star>, + list, one<'|'>, star>>> { }; @@ -1107,117 +962,102 @@ struct directive_definition_start }; struct directive_definition_content - : seq, one<'@'>, directive_name, opt, arguments_definition>, plus, on_keyword, plus, directive_locations> + : seq, one<'@'>, directive_name, opt, arguments_definition>, + plus, on_keyword, plus, directive_locations> { }; // https://facebook.github.io/graphql/June2018/#DirectiveDefinition -struct directive_definition - : if_must +struct directive_definition : if_must { }; // https://facebook.github.io/graphql/June2018/#TypeSystemDefinition -struct type_system_definition - : sor +struct type_system_definition : sor { }; -struct extend_keyword - : TAO_PEGTL_KEYWORD("extend") +struct extend_keyword : TAO_PEGTL_KEYWORD("extend") { }; // https://facebook.github.io/graphql/June2018/#OperationTypeDefinition -struct operation_type_definition - : root_operation_definition +struct operation_type_definition : root_operation_definition { }; -struct schema_extension_start - : seq, schema_keyword> +struct schema_extension_start : seq, schema_keyword> { }; struct schema_extension_operation_type_definitions - : seq, star, list>, star, must>> + : seq, star, list>, star, + must>> { }; struct schema_extension_content : seq, - sor, schema_extension_operation_type_definitions> - , directives>> + sor, schema_extension_operation_type_definitions>, directives>> { }; // https://facebook.github.io/graphql/June2018/#SchemaExtension -struct schema_extension - : if_must +struct schema_extension : if_must { }; -struct scalar_type_extension_start - : seq, scalar_keyword> +struct scalar_type_extension_start : seq, scalar_keyword> { }; -struct scalar_type_extension_content - : seq, scalar_name, star, directives> +struct scalar_type_extension_content : seq, scalar_name, star, directives> { }; // https://facebook.github.io/graphql/June2018/#ScalarTypeExtension -struct scalar_type_extension - : if_must +struct scalar_type_extension : if_must { }; -struct object_type_extension_start - : seq, type_keyword> +struct object_type_extension_start : seq, type_keyword> { }; -struct object_type_extension_implements_interfaces - : seq, implements_interfaces> +struct object_type_extension_implements_interfaces : seq, implements_interfaces> { }; -struct object_type_extension_directives - : seq, directives> +struct object_type_extension_directives : seq, directives> { }; -struct object_type_extension_fields_definition - : seq, fields_definition> +struct object_type_extension_fields_definition : seq, fields_definition> { }; struct object_type_extension_content : seq, object_name, - sor, opt, object_type_extension_fields_definition> - , seq, object_type_extension_directives> - , object_type_extension_implements_interfaces>> + sor, + opt, object_type_extension_fields_definition>, + seq, + object_type_extension_directives>, + object_type_extension_implements_interfaces>> { }; // https://facebook.github.io/graphql/June2018/#ObjectTypeExtension -struct object_type_extension - : if_must +struct object_type_extension : if_must { }; -struct interface_type_extension_start - : seq, interface_keyword> +struct interface_type_extension_start : seq, interface_keyword> { }; struct interface_type_extension_content : seq, interface_name, star, - sor>, fields_definition> - , directives>> + sor>, fields_definition>, directives>> { }; @@ -1227,51 +1067,43 @@ struct interface_type_extension { }; -struct union_type_extension_start - : seq, union_keyword> +struct union_type_extension_start : seq, union_keyword> { }; struct union_type_extension_content : seq, union_name, star, - sor>, union_member_types> - , directives>> + sor>, union_member_types>, directives>> { }; // https://facebook.github.io/graphql/June2018/#UnionTypeExtension -struct union_type_extension - : if_must +struct union_type_extension : if_must { }; -struct enum_type_extension_start - : seq, enum_keyword> +struct enum_type_extension_start : seq, enum_keyword> { }; struct enum_type_extension_content : seq, enum_name, star, - sor>, enum_values_definition> - , directives>> + sor>, enum_values_definition>, directives>> { }; // https://facebook.github.io/graphql/June2018/#EnumTypeExtension -struct enum_type_extension - : if_must +struct enum_type_extension : if_must { }; -struct input_object_type_extension_start - : seq, input_keyword> +struct input_object_type_extension_start : seq, input_keyword> { }; struct input_object_type_extension_content : seq, object_name, star, - sor>, input_fields_definition> - , directives>> + sor>, input_fields_definition>, directives>> { }; @@ -1283,38 +1115,29 @@ struct input_object_type_extension // https://facebook.github.io/graphql/June2018/#TypeExtension struct type_extension - : sor + : sor { }; // https://facebook.github.io/graphql/June2018/#TypeSystemExtension -struct type_system_extension - : sor +struct type_system_extension : sor { }; // https://facebook.github.io/graphql/June2018/#Definition -struct definition - : sor +struct definition : sor { }; struct document_content - : seq, star, list>, star, tao::graphqlpeg::eof> + : seq, star, list>, star, + tao::graphqlpeg::eof> { }; // https://facebook.github.io/graphql/June2018/#Document -struct document - : must +struct document : must { }; diff --git a/include/graphqlservice/GraphQLResponse.h b/include/graphqlservice/GraphQLResponse.h index 91ec497a..24e0214a 100644 --- a/include/graphqlservice/GraphQLResponse.h +++ b/include/graphqlservice/GraphQLResponse.h @@ -20,7 +20,8 @@ #include #include -#include +#include +#include #include namespace graphql::response { @@ -109,8 +110,6 @@ struct ValueTypeTraits // ID values are represented as a String, there's no separate handling of this type. }; -struct TypedData; - // Represent a discriminated union of GraphQL response value types. struct Value { @@ -147,10 +146,10 @@ struct Value // Valid for Type::Map GRAPHQLRESPONSE_EXPORT void emplace_back(std::string&& name, Value&& value); - GRAPHQLRESPONSE_EXPORT MapType::const_iterator find(const std::string& name) const; + GRAPHQLRESPONSE_EXPORT MapType::const_iterator find(std::string_view name) const; GRAPHQLRESPONSE_EXPORT MapType::const_iterator begin() const; GRAPHQLRESPONSE_EXPORT MapType::const_iterator end() const; - GRAPHQLRESPONSE_EXPORT const Value& operator[](const std::string& name) const; + GRAPHQLRESPONSE_EXPORT const Value& operator[](std::string_view name) const; // Valid for Type::List GRAPHQLRESPONSE_EXPORT void emplace_back(Value&& value); @@ -194,8 +193,45 @@ struct Value } private: - const Type _type; - std::unique_ptr _data; + // Type::Map + struct MapData + { + bool operator==(const MapData& rhs) const; + + MapType map; + std::vector members; + }; + + // Type::String + struct StringData + { + bool operator==(const StringData& rhs) const; + + StringType string; + bool from_json = false; + }; + + // Type::Null + struct NullData + { + bool operator==(const NullData& rhs) const; + }; + + // Type::EnumValue + using EnumData = StringType; + + // Type::Scalar + struct ScalarData + { + bool operator==(const ScalarData& rhs) const; + + std::unique_ptr scalar; + }; + + using TypeData = std::variant; + + TypeData _data; }; #ifdef GRAPHQL_DLLEXPORTS diff --git a/include/graphqlservice/GraphQLSchema.h b/include/graphqlservice/GraphQLSchema.h new file mode 100644 index 00000000..2a4e9212 --- /dev/null +++ b/include/graphqlservice/GraphQLSchema.h @@ -0,0 +1,409 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef GRAPHQLSCHEMA_H +#define GRAPHQLSCHEMA_H + +#include "graphqlservice/GraphQLService.h" + +#include + +namespace graphql { +namespace introspection { + +enum class TypeKind; +enum class DirectiveLocation; + +} // namespace introspection + +namespace schema { + +class Schema; +class Directive; +class BaseType; +class ScalarType; +class ObjectType; +class InterfaceType; +class UnionType; +class EnumType; +class InputObjectType; +class WrapperType; +class Field; +class InputValue; +class EnumValue; + +class Schema : public std::enable_shared_from_this +{ +public: + GRAPHQLSERVICE_EXPORT explicit Schema(bool noIntrospection = false); + + GRAPHQLSERVICE_EXPORT void AddQueryType(std::shared_ptr query); + GRAPHQLSERVICE_EXPORT void AddMutationType(std::shared_ptr mutation); + GRAPHQLSERVICE_EXPORT void AddSubscriptionType(std::shared_ptr subscription); + GRAPHQLSERVICE_EXPORT void AddType(std::string_view name, std::shared_ptr type); + GRAPHQLSERVICE_EXPORT const std::shared_ptr& LookupType( + std::string_view name) const; + GRAPHQLSERVICE_EXPORT const std::shared_ptr& WrapType( + introspection::TypeKind kind, const std::shared_ptr& ofType); + GRAPHQLSERVICE_EXPORT void AddDirective(std::shared_ptr directive); + + // Accessors + GRAPHQLSERVICE_EXPORT bool supportsIntrospection() const noexcept; + GRAPHQLSERVICE_EXPORT const std::vector< + std::pair>>& + types() const noexcept; + GRAPHQLSERVICE_EXPORT const std::shared_ptr& queryType() const noexcept; + GRAPHQLSERVICE_EXPORT const std::shared_ptr& mutationType() const noexcept; + GRAPHQLSERVICE_EXPORT const std::shared_ptr& subscriptionType() + const noexcept; + GRAPHQLSERVICE_EXPORT const std::vector>& directives() + const noexcept; + +private: + const bool _noIntrospection = false; + + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; + std::unordered_map _typeMap; + std::vector>> _types; + std::vector> _directives; + std::unordered_map, std::shared_ptr> + _nonNullWrappers; + std::unordered_map, std::shared_ptr> + _listWrappers; +}; + +class BaseType : public std::enable_shared_from_this +{ +public: + // Accessors + GRAPHQLSERVICE_EXPORT introspection::TypeKind kind() const noexcept; + GRAPHQLSERVICE_EXPORT virtual std::string_view name() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::vector>& fields() + const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::vector>& + interfaces() const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::vector>& possibleTypes() + const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::vector>& enumValues() + const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::vector>& + inputFields() const noexcept; + GRAPHQLSERVICE_EXPORT virtual const std::weak_ptr& ofType() const noexcept; + +protected: + BaseType(introspection::TypeKind kind, std::string_view description); + +private: + const introspection::TypeKind _kind; + const std::string_view _description; +}; + +class ScalarType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit ScalarType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + +private: + const std::string_view _name; +}; + +class ObjectType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit ObjectType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + GRAPHQLSERVICE_EXPORT void AddInterfaces( + std::initializer_list> interfaces); + GRAPHQLSERVICE_EXPORT void AddFields(std::initializer_list> fields); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& fields() + const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& interfaces() + const noexcept final; + +private: + const std::string_view _name; + + std::vector> _interfaces; + std::vector> _fields; +}; + +class InterfaceType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit InterfaceType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + GRAPHQLSERVICE_EXPORT void AddPossibleType(std::weak_ptr possibleType); + GRAPHQLSERVICE_EXPORT void AddFields(std::initializer_list> fields); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& fields() + const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& possibleTypes() + const noexcept final; + +private: + const std::string_view _name; + + std::vector> _fields; + std::vector> _possibleTypes; +}; + +class UnionType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit UnionType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + GRAPHQLSERVICE_EXPORT void AddPossibleTypes( + std::initializer_list> possibleTypes); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& possibleTypes() + const noexcept final; + +private: + const std::string_view _name; + + std::vector> _possibleTypes; +}; + +struct EnumValueType +{ + std::string_view value; + std::string_view description; + std::optional deprecationReason; +}; + +class EnumType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit EnumType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + GRAPHQLSERVICE_EXPORT void AddEnumValues(std::initializer_list enumValues); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& enumValues() + const noexcept final; + +private: + const std::string_view _name; + + std::vector> _enumValues; +}; + +class InputObjectType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit InputObjectType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + std::string_view name, std::string_view description); + + GRAPHQLSERVICE_EXPORT void AddInputValues( + std::initializer_list> inputValues); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept final; + GRAPHQLSERVICE_EXPORT const std::vector>& inputFields() + const noexcept final; + +private: + const std::string_view _name; + + std::vector> _inputValues; +}; + +class WrapperType : public BaseType +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit WrapperType(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make( + introspection::TypeKind kind, const std::shared_ptr& ofType); + + // Accessors + GRAPHQLSERVICE_EXPORT const std::weak_ptr& ofType() const noexcept final; + +private: + const std::weak_ptr _ofType; +}; + +class Field : public std::enable_shared_from_this +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit Field(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make(std::string_view name, + std::string_view description, std::optional deprecationReason, + const std::shared_ptr& type, + std::initializer_list> args = {}); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; + GRAPHQLSERVICE_EXPORT const std::vector>& args() + const noexcept; + GRAPHQLSERVICE_EXPORT const std::weak_ptr& type() const noexcept; + GRAPHQLSERVICE_EXPORT const std::optional& deprecationReason() const noexcept; + +private: + const std::string_view _name; + const std::string_view _description; + const std::optional _deprecationReason; + const std::weak_ptr _type; + const std::vector> _args; +}; + +class InputValue : public std::enable_shared_from_this +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit InputValue(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make(std::string_view name, + std::string_view description, const std::shared_ptr& type, + std::string_view defaultValue); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; + GRAPHQLSERVICE_EXPORT const std::weak_ptr& type() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view defaultValue() const noexcept; + +private: + const std::string_view _name; + const std::string_view _description; + const std::weak_ptr _type; + const std::string_view _defaultValue; +}; + +class EnumValue : public std::enable_shared_from_this +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit EnumValue(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make(std::string_view name, + std::string_view description, std::optional deprecationReason); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; + GRAPHQLSERVICE_EXPORT const std::optional& deprecationReason() const noexcept; + +private: + const std::string_view _name; + const std::string_view _description; + const std::optional _deprecationReason; +}; + +class Directive : public std::enable_shared_from_this +{ +private: + // Use a private constructor parameter type to enable std::make_shared inside of the static Make + // method without exposing the constructor as part of the public interface. + struct init; + +public: + explicit Directive(init&& params); + + GRAPHQLSERVICE_EXPORT static std::shared_ptr Make(std::string_view name, + std::string_view description, + std::initializer_list locations, + std::initializer_list> args = {}); + + // Accessors + GRAPHQLSERVICE_EXPORT std::string_view name() const noexcept; + GRAPHQLSERVICE_EXPORT std::string_view description() const noexcept; + GRAPHQLSERVICE_EXPORT const std::vector& locations() + const noexcept; + GRAPHQLSERVICE_EXPORT const std::vector>& args() + const noexcept; + +private: + const std::string_view _name; + const std::string_view _description; + const std::vector _locations; + const std::vector> _args; +}; + +} // namespace schema +} // namespace graphql + +#endif // GRAPHQLSCHEMA_H diff --git a/include/graphqlservice/GraphQLService.h b/include/graphqlservice/GraphQLService.h index b8d2add7..5b5e9ea2 100644 --- a/include/graphqlservice/GraphQLService.h +++ b/include/graphqlservice/GraphQLService.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -40,24 +39,24 @@ #include #include -namespace graphql::service { +namespace graphql { +namespace schema { -// Errors should have a message string, and optional locations and a path. -GRAPHQLSERVICE_EXPORT void addErrorMessage(std::string&& message, response::Value& error); +class Schema; + +} // namespace schema + +namespace service { +// Errors should have a message string, and optional locations and a path. struct schema_location { size_t line = 0; size_t column = 1; }; -GRAPHQLSERVICE_EXPORT void addErrorLocation( - const schema_location& location, response::Value& error); - -using path_segment = std::variant; -using field_path = std::queue; - -GRAPHQLSERVICE_EXPORT void addErrorPath(field_path&& path, response::Value& error); +using path_segment = std::variant; +using field_path = std::vector; struct schema_error { @@ -80,17 +79,13 @@ class schema_exception : public std::exception GRAPHQLSERVICE_EXPORT const char* what() const noexcept override; - GRAPHQLSERVICE_EXPORT const std::vector& getStructuredErrors() const noexcept; GRAPHQLSERVICE_EXPORT std::vector getStructuredErrors() noexcept; - - GRAPHQLSERVICE_EXPORT const response::Value& getErrors() const noexcept; - GRAPHQLSERVICE_EXPORT response::Value getErrors() noexcept; + GRAPHQLSERVICE_EXPORT response::Value getErrors() const; private: static std::vector convertMessages(std::vector&& messages) noexcept; std::vector _structuredErrors; - response::Value _errors; }; // The RequestState is nullable, but if you have multiple threads processing requests and there's @@ -225,7 +220,7 @@ class Fragment // Resolvers for complex types need to be able to find fragment definitions anywhere in // the request document by name. -using FragmentMap = std::unordered_map; +using FragmentMap = std::unordered_map; // Resolver functors take a set of arguments encoded as members on a JSON object // with an optional selection set for complex types and return a JSON value for @@ -252,7 +247,15 @@ struct ResolverParams : SelectionSetParams const response::Value& variables; }; -using Resolver = std::function(ResolverParams&&)>; +// Propagate data and errors together without bundling them into a response::Value struct until +// we're ready to return from the top level Operation. +struct ResolverResult +{ + response::Value data; + std::vector errors; +}; + +using Resolver = std::function(ResolverParams&&)>; using ResolverMap = std::vector>; // Binary data and opaque strings like IDs are encoded in Base64. @@ -472,7 +475,7 @@ GRAPHQLSERVICE_EXPORT response::Value ModifiedArgument::convert // Each type should handle fragments with type conditions matching its own // name and any inheritted interfaces. -using TypeNames = std::unordered_set; +using TypeNames = std::unordered_set; // Object parses argument values, performs variable lookups, expands fragments, evaluates @include // and @skip directives, and calls through to the resolver functor for each selected field with @@ -484,7 +487,7 @@ class Object : public std::enable_shared_from_this GRAPHQLSERVICE_EXPORT explicit Object(TypeNames&& typeNames, ResolverMap&& resolvers); GRAPHQLSERVICE_EXPORT virtual ~Object() = default; - GRAPHQLSERVICE_EXPORT std::future resolve( + GRAPHQLSERVICE_EXPORT std::future resolve( const SelectionSetParams& selectionSetParams, const peg::ast_node& selection, const FragmentMap& fragments, const response::Value& variables) const; @@ -539,14 +542,14 @@ struct ModifiedResult }; // Convert a single value of the specified type to JSON. - static std::future convert( + static std::future convert( typename ResultTraits::future_type result, ResolverParams&& params); // Peel off the none modifier. If it's included, it should always be last in the list. template static typename std::enable_if_t && std::is_base_of_v, - std::future> + std::future> convert(FieldResult::type>&& result, ResolverParams&& params) { // Call through to the Object specialization with a static_pointer_cast for subclasses of @@ -567,7 +570,7 @@ struct ModifiedResult template static typename std::enable_if_t || !std::is_base_of_v), - std::future> + std::future> convert(typename ResultTraits::future_type result, ResolverParams&& params) { // Just call through to the partial specialization without the modifier. @@ -578,7 +581,7 @@ struct ModifiedResult template static typename std::enable_if_t, typename ResultTraits::type>, - std::future> + std::future> convert(typename ResultTraits::future_type result, ResolverParams&& params) { @@ -589,11 +592,7 @@ struct ModifiedResult if (!wrappedResult) { - response::Value document(response::Type::Map); - - document.emplace_back(std::string { strData }, response::Value()); - - return document; + return ResolverResult {}; } std::promise::type> promise; @@ -612,7 +611,7 @@ struct ModifiedResult template static typename std::enable_if_t, typename ResultTraits::type>, - std::future> + std::future> convert(typename ResultTraits::future_type result, ResolverParams&& params) { @@ -627,11 +626,7 @@ struct ModifiedResult if (!wrappedResult) { - response::Value document(response::Type::Map); - - document.emplace_back(std::string { strData }, response::Value()); - - return document; + return ResolverResult {}; } std::promise::type> promise; @@ -648,7 +643,7 @@ struct ModifiedResult // Peel off list modifiers. template - static typename std::enable_if_t> + static typename std::enable_if_t> convert(typename ResultTraits::future_type result, ResolverParams&& params) { @@ -656,9 +651,10 @@ struct ModifiedResult params.launch, [](auto&& wrappedFuture, ResolverParams&& wrappedParams) { auto wrappedResult = wrappedFuture.get(); - std::queue> children; + std::vector> children; - wrappedParams.errorPath.push(size_t { 0 }); + children.reserve(wrappedResult.size()); + wrappedParams.errorPath.push_back(size_t { 0 }); using vector_type = std::decay_t; @@ -670,7 +666,7 @@ struct ModifiedResult // Copy the values from the std::vector<> rather than moving them. for (typename vector_type::value_type entry : wrappedResult) { - children.push(ModifiedResult::convert(std::move(entry), + children.push_back(ModifiedResult::convert(std::move(entry), ResolverParams(wrappedParams))); ++std::get(wrappedParams.errorPath.back()); } @@ -679,62 +675,44 @@ struct ModifiedResult { for (auto& entry : wrappedResult) { - children.push(ModifiedResult::convert(std::move(entry), + children.push_back(ModifiedResult::convert(std::move(entry), ResolverParams(wrappedParams))); ++std::get(wrappedParams.errorPath.back()); } } - response::Value data(response::Type::List); - response::Value errors(response::Type::List); + ResolverResult document { response::Value { response::Type::List } }; wrappedParams.errorPath.back() = size_t { 0 }; - while (!children.empty()) + for (auto& child : children) { try { - auto value = children.front().get(); - auto members = value.release(); + auto value = child.get(); - for (auto& entry : members) - { - if (entry.second.type() == response::Type::List - && entry.first == strErrors) - { - auto errorEntries = entry.second.release(); + document.data.emplace_back(std::move(value.data)); - for (auto& errorEntry : errorEntries) - { - errors.emplace_back(std::move(errorEntry)); - } - } - else if (entry.first == strData) + if (!value.errors.empty()) + { + document.errors.reserve(document.errors.size() + value.errors.size()); + for (auto& error : value.errors) { - data.emplace_back(std::move(entry.second)); + document.errors.push_back(std::move(error)); } } } catch (schema_exception& scx) { - auto messages = scx.getStructuredErrors(); + auto errors = scx.getStructuredErrors(); - errors.reserve(errors.size() + messages.size()); - for (auto& message : messages) + if (!errors.empty()) { - response::Value error(response::Type::Map); - - error.reserve(3); - addErrorMessage(std::move(message.message), error); - addErrorLocation(message.location.line > 0 - ? message.location - : wrappedParams.getLocation(), - error); - addErrorPath(field_path { message.path.empty() ? wrappedParams.errorPath - : message.path }, - error); - - errors.emplace_back(std::move(error)); + document.errors.reserve(document.errors.size() + errors.size()); + for (auto& error : errors) + { + document.errors.push_back(std::move(error)); + } } } catch (const std::exception& ex) @@ -744,31 +722,14 @@ struct ModifiedResult message << "Field error name: " << wrappedParams.fieldName << " unknown error: " << ex.what(); - schema_location location = wrappedParams.getLocation(); - response::Value error(response::Type::Map); - - error.reserve(3); - addErrorMessage(message.str(), error); - addErrorLocation(location, error); - addErrorPath(field_path { wrappedParams.errorPath }, error); - - errors.emplace_back(std::move(error)); + document.errors.emplace_back(schema_error { message.str(), + wrappedParams.getLocation(), + wrappedParams.errorPath }); } - children.pop(); ++std::get(wrappedParams.errorPath.back()); } - response::Value document(response::Type::Map); - - document.reserve(2); - document.emplace_back(std::string { strData }, std::move(data)); - - if (errors.size() > 0) - { - document.emplace_back(std::string { strErrors }, std::move(errors)); - } - return document; }, std::move(result), @@ -779,7 +740,7 @@ struct ModifiedResult using ResolverCallback = std::function::type&&, const ResolverParams&)>; - static std::future resolve(typename ResultTraits::future_type result, + static std::future resolve(typename ResultTraits::future_type result, ResolverParams&& params, ResolverCallback&& resolver) { static_assert(!std::is_base_of_v, @@ -789,32 +750,23 @@ struct ModifiedResult [](auto&& resultFuture, ResolverParams&& paramsFuture, ResolverCallback&& resolverFuture) noexcept { - response::Value data; - response::Value errors(response::Type::List); + ResolverResult document; try { - data = resolverFuture(resultFuture.get(), paramsFuture); + document.data = resolverFuture(resultFuture.get(), paramsFuture); } catch (schema_exception& scx) { - auto messages = scx.getStructuredErrors(); + auto errors = scx.getStructuredErrors(); - errors.reserve(errors.size() + messages.size()); - for (auto& message : messages) + if (!errors.empty()) { - response::Value error(response::Type::Map); - - error.reserve(3); - addErrorMessage(std::move(message.message), error); - addErrorLocation(message.location.line > 0 ? message.location - : paramsFuture.getLocation(), - error); - addErrorPath(field_path { message.path.empty() ? paramsFuture.errorPath - : message.path }, - error); - - errors.emplace_back(std::move(error)); + document.errors.reserve(document.errors.size() + errors.size()); + for (auto& error : errors) + { + document.errors.push_back(std::move(error)); + } } } catch (const std::exception& ex) @@ -824,24 +776,9 @@ struct ModifiedResult message << "Field name: " << paramsFuture.fieldName << " unknown error: " << ex.what(); - response::Value error(response::Type::Map); - - error.reserve(3); - addErrorMessage(message.str(), error); - addErrorLocation(paramsFuture.getLocation(), error); - addErrorPath(std::move(paramsFuture.errorPath), error); - - errors.emplace_back(std::move(error)); - } - - response::Value document(response::Type::Map); - - document.reserve(2); - document.emplace_back(std::string { strData }, std::move(data)); - - if (errors.size() > 0) - { - document.emplace_back(std::string { strErrors }, std::move(errors)); + document.errors.emplace_back(schema_error { message.str(), + paramsFuture.getLocation(), + std::move(paramsFuture.errorPath) }); } return document; @@ -866,29 +803,29 @@ using ObjectResult = ModifiedResult; #ifdef GRAPHQL_DLLEXPORTS // Export all of the built-in converters template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params); template <> -GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( +GRAPHQLSERVICE_EXPORT std::future ModifiedResult::convert( FieldResult>&& result, ResolverParams&& params); #endif // GRAPHQL_DLLEXPORTS -using TypeMap = std::unordered_map>; +using TypeMap = std::unordered_map>; // You can still sub-class RequestState and use that in the state parameter to Request::subscribe // to add your own state to the service callbacks that you receive while executing the subscription @@ -921,7 +858,7 @@ struct OperationData : std::enable_shared_from_this // Subscription callbacks receive the response::Value representing the result of evaluating the // SelectionSet against the payload. using SubscriptionCallback = std::function)>; -using SubscriptionArguments = std::unordered_map; +using SubscriptionArguments = std::unordered_map; using SubscriptionFilterCallback = std::function; // Subscriptions are stored in maps using these keys. @@ -956,14 +893,15 @@ class ValidateExecutableVisitor; class Request : public std::enable_shared_from_this { protected: - GRAPHQLSERVICE_EXPORT explicit Request(TypeMap&& operationTypes); + GRAPHQLSERVICE_EXPORT explicit Request( + TypeMap&& operationTypes, const std::shared_ptr& schema); GRAPHQLSERVICE_EXPORT virtual ~Request(); public: GRAPHQLSERVICE_EXPORT std::vector validate(peg::ast& query) const; - GRAPHQLSERVICE_EXPORT std::pair findOperationDefinition( - const peg::ast_node& root, const std::string& operationName) const; + GRAPHQLSERVICE_EXPORT std::pair findOperationDefinition( + peg::ast& query, std::string_view operationName) const; GRAPHQLSERVICE_EXPORT std::future resolve( const std::shared_ptr& state, peg::ast& query, @@ -1012,6 +950,11 @@ class Request : public std::enable_shared_from_this const SubscriptionFilterCallback& applyDirectives, const std::shared_ptr& subscriptionObject) const; + [[deprecated( + "Use the Request::findOperationDefinition overload which takes a peg::ast reference and " + "string_view instead.")]] GRAPHQLSERVICE_EXPORT std::pair + findOperationDefinition(const peg::ast_node& root, const std::string& operationName) const; + [[deprecated("Use the Request::resolve overload which takes a peg::ast reference " "instead.")]] GRAPHQLSERVICE_EXPORT std::future resolve(const std::shared_ptr& state, const peg::ast_node& root, @@ -1023,17 +966,21 @@ class Request : public std::enable_shared_from_this response::Value&& variables) const; private: - std::future resolveValidated(std::launch launch, + std::pair findUnvalidatedOperationDefinition( + const peg::ast_node& root, const std::string& operationName) const; + + std::future resolveUnvalidated(std::launch launch, const std::shared_ptr& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const; - TypeMap _operations; + const TypeMap _operations; std::unique_ptr _validation; std::map> _subscriptions; - std::unordered_map> _listeners; + std::unordered_map> _listeners; SubscriptionKey _nextKey = 0; }; -} /* namespace graphql::service */ +} // namespace service +} // namespace graphql #endif // GRAPHQLSERVICE_H diff --git a/include/graphqlservice/Introspection.h b/include/graphqlservice/Introspection.h deleted file mode 100644 index 1a2f1795..00000000 --- a/include/graphqlservice/Introspection.h +++ /dev/null @@ -1,354 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. - -#pragma once - -#ifndef INTROSPECTION_H -#define INTROSPECTION_H - -#include "graphqlservice/IntrospectionSchema.h" - -namespace graphql::introspection { - -class Schema; -class Directive; -class ScalarType; -class ObjectType; -class InterfaceType; -class UnionType; -class EnumType; -class InputObjectType; -class WrapperType; -class Field; -class InputValue; -class EnumValue; - -class Schema : public object::Schema -{ -public: - GRAPHQLSERVICE_EXPORT explicit Schema(); - - GRAPHQLSERVICE_EXPORT void AddQueryType(std::shared_ptr query); - GRAPHQLSERVICE_EXPORT void AddMutationType(std::shared_ptr mutation); - GRAPHQLSERVICE_EXPORT void AddSubscriptionType(std::shared_ptr subscription); - GRAPHQLSERVICE_EXPORT void AddType( - response::StringType&& name, std::shared_ptr type); - GRAPHQLSERVICE_EXPORT const std::shared_ptr& LookupType( - const response::StringType& name) const; - GRAPHQLSERVICE_EXPORT const std::shared_ptr& WrapType( - TypeKind kind, const std::shared_ptr& ofType); - GRAPHQLSERVICE_EXPORT void AddDirective(std::shared_ptr directive); - - // Accessors - service::FieldResult>> getTypes( - service::FieldParams&& params) const override; - service::FieldResult> getQueryType( - service::FieldParams&& params) const override; - service::FieldResult> getMutationType( - service::FieldParams&& params) const override; - service::FieldResult> getSubscriptionType( - service::FieldParams&& params) const override; - service::FieldResult>> getDirectives( - service::FieldParams&& params) const override; - -private: - std::shared_ptr _query; - std::shared_ptr _mutation; - std::shared_ptr _subscription; - std::unordered_map _typeMap; - std::vector>> _types; - std::vector> _directives; - std::unordered_map, std::shared_ptr> - _nonNullWrappers; - std::unordered_map, std::shared_ptr> _listWrappers; -}; - -class BaseType : public object::Type -{ -public: - // Accessors - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult>>> getFields( - service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> getInterfaces( - service::FieldParams&& params) const override; - service::FieldResult>>> - getPossibleTypes(service::FieldParams&& params) const override; - service::FieldResult>>> - getEnumValues(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> - getInputFields(service::FieldParams&& params) const override; - service::FieldResult> getOfType( - service::FieldParams&& params) const override; - -protected: - BaseType(response::StringType&& description); - -private: - const response::StringType _description; -}; - -class ScalarType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit ScalarType( - response::StringType&& name, response::StringType&& description); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; -}; - -class ObjectType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit ObjectType( - response::StringType&& name, response::StringType&& description); - - GRAPHQLSERVICE_EXPORT void AddInterfaces( - std::vector> interfaces); - GRAPHQLSERVICE_EXPORT void AddFields(std::vector> fields); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult>>> getFields( - service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> getInterfaces( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; - - std::vector> _interfaces; - std::vector> _fields; -}; - -class InterfaceType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit InterfaceType( - response::StringType&& name, response::StringType&& description); - - GRAPHQLSERVICE_EXPORT void AddPossibleType(std::weak_ptr possibleType); - GRAPHQLSERVICE_EXPORT void AddFields(std::vector> fields); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult>>> getFields( - service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - service::FieldResult>>> - getPossibleTypes(service::FieldParams&& params) const override; - -private: - const response::StringType _name; - - std::vector> _fields; - std::vector> _possibleTypes; -}; - -class UnionType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit UnionType( - response::StringType&& name, response::StringType&& description); - - GRAPHQLSERVICE_EXPORT void AddPossibleTypes( - std::vector> possibleTypes); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult>>> - getPossibleTypes(service::FieldParams&& params) const override; - -private: - const response::StringType _name; - - std::vector> _possibleTypes; -}; - -struct EnumValueType -{ - response::StringType value; - response::StringType description; - std::optional deprecationReason; -}; - -class EnumType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit EnumType( - response::StringType&& name, response::StringType&& description); - - GRAPHQLSERVICE_EXPORT void AddEnumValues(std::vector enumValues); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult>>> - getEnumValues(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const override; - -private: - const response::StringType _name; - - std::vector> _enumValues; -}; - -class InputObjectType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit InputObjectType( - response::StringType&& name, response::StringType&& description); - - GRAPHQLSERVICE_EXPORT void AddInputValues(std::vector> inputValues); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getName( - service::FieldParams&& params) const override; - service::FieldResult>>> - getInputFields(service::FieldParams&& params) const override; - -private: - const response::StringType _name; - - std::vector> _inputValues; -}; - -class WrapperType : public BaseType -{ -public: - GRAPHQLSERVICE_EXPORT explicit WrapperType( - TypeKind kind, const std::shared_ptr& ofType); - - // Accessors - service::FieldResult getKind(service::FieldParams&& params) const override; - service::FieldResult> getOfType( - service::FieldParams&& params) const override; - -private: - const TypeKind _kind; - const std::weak_ptr _ofType; -}; - -class Field : public object::Field -{ -public: - GRAPHQLSERVICE_EXPORT explicit Field(response::StringType&& name, - response::StringType&& description, std::optional&& deprecationReason, - std::vector>&& args, const std::shared_ptr& type); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult>> getArgs( - service::FieldParams&& params) const override; - service::FieldResult> getType( - service::FieldParams&& params) const override; - service::FieldResult getIsDeprecated( - service::FieldParams&& params) const override; - service::FieldResult> getDeprecationReason( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; - const response::StringType _description; - const std::optional _deprecationReason; - const std::vector> _args; - const std::weak_ptr _type; -}; - -class InputValue : public object::InputValue -{ -public: - GRAPHQLSERVICE_EXPORT explicit InputValue(response::StringType&& name, - response::StringType&& description, const std::shared_ptr& type, - response::StringType&& defaultValue); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult> getType( - service::FieldParams&& params) const override; - service::FieldResult> getDefaultValue( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; - const response::StringType _description; - const std::weak_ptr _type; - const response::StringType _defaultValue; -}; - -class EnumValue : public object::EnumValue -{ -public: - GRAPHQLSERVICE_EXPORT explicit EnumValue(response::StringType&& name, - response::StringType&& description, - std::optional&& deprecationReason); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult getIsDeprecated( - service::FieldParams&& params) const override; - service::FieldResult> getDeprecationReason( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; - const response::StringType _description; - const std::optional _deprecationReason; -}; - -class Directive : public object::Directive -{ -public: - GRAPHQLSERVICE_EXPORT explicit Directive(response::StringType&& name, - response::StringType&& description, std::vector&& locations, - std::vector>&& args); - - // Accessors - service::FieldResult getName( - service::FieldParams&& params) const override; - service::FieldResult> getDescription( - service::FieldParams&& params) const override; - service::FieldResult> getLocations( - service::FieldParams&& params) const override; - service::FieldResult>> getArgs( - service::FieldParams&& params) const override; - -private: - const response::StringType _name; - const response::StringType _description; - const std::vector _locations; - const std::vector> _args; -}; - -} /* namespace graphql::introspection */ - -#endif // INTROSPECTION_H diff --git a/include/graphqlservice/introspection/Introspection.h b/include/graphqlservice/introspection/Introspection.h new file mode 100644 index 00000000..7b80aaa6 --- /dev/null +++ b/include/graphqlservice/introspection/Introspection.h @@ -0,0 +1,157 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef INTROSPECTION_H +#define INTROSPECTION_H + +#include "graphqlservice/GraphQLSchema.h" +#include "graphqlservice/introspection/IntrospectionSchema.h" + +namespace graphql::introspection { + +class Schema; +class Directive; +class Type; +class Field; +class InputValue; +class EnumValue; + +class Schema : public object::Schema +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Schema(const std::shared_ptr& schema); + + // Accessors + service::FieldResult>> getTypes( + service::FieldParams&& params) const override; + service::FieldResult> getQueryType( + service::FieldParams&& params) const override; + service::FieldResult> getMutationType( + service::FieldParams&& params) const override; + service::FieldResult> getSubscriptionType( + service::FieldParams&& params) const override; + service::FieldResult>> getDirectives( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _schema; +}; + +class Type : public object::Type +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Type(const std::shared_ptr& type); + + // Accessors + service::FieldResult getKind(service::FieldParams&&) const override; + service::FieldResult> getName( + service::FieldParams&& params) const override; + service::FieldResult> getDescription( + service::FieldParams&& params) const override; + service::FieldResult>>> getFields( + service::FieldParams&& params, + std::optional&& includeDeprecatedArg) const override; + service::FieldResult>>> getInterfaces( + service::FieldParams&& params) const override; + service::FieldResult>>> + getPossibleTypes(service::FieldParams&& params) const override; + service::FieldResult>>> + getEnumValues(service::FieldParams&& params, + std::optional&& includeDeprecatedArg) const override; + service::FieldResult>>> + getInputFields(service::FieldParams&& params) const override; + service::FieldResult> getOfType( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _type; +}; + +class Field : public object::Field +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Field(const std::shared_ptr& field); + + // Accessors + service::FieldResult getName( + service::FieldParams&& params) const override; + service::FieldResult> getDescription( + service::FieldParams&& params) const override; + service::FieldResult>> getArgs( + service::FieldParams&& params) const override; + service::FieldResult> getType( + service::FieldParams&& params) const override; + service::FieldResult getIsDeprecated( + service::FieldParams&& params) const override; + service::FieldResult> getDeprecationReason( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _field; +}; + +class InputValue : public object::InputValue +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit InputValue( + const std::shared_ptr& inputValue); + + // Accessors + service::FieldResult getName( + service::FieldParams&& params) const override; + service::FieldResult> getDescription( + service::FieldParams&& params) const override; + service::FieldResult> getType( + service::FieldParams&& params) const override; + service::FieldResult> getDefaultValue( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _inputValue; +}; + +class EnumValue : public object::EnumValue +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit EnumValue( + const std::shared_ptr& enumValue); + + // Accessors + service::FieldResult getName( + service::FieldParams&& params) const override; + service::FieldResult> getDescription( + service::FieldParams&& params) const override; + service::FieldResult getIsDeprecated( + service::FieldParams&& params) const override; + service::FieldResult> getDeprecationReason( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _enumValue; +}; + +class Directive : public object::Directive +{ +public: + GRAPHQLINTROSPECTION_EXPORT explicit Directive( + const std::shared_ptr& directive); + + // Accessors + service::FieldResult getName( + service::FieldParams&& params) const override; + service::FieldResult> getDescription( + service::FieldParams&& params) const override; + service::FieldResult> getLocations( + service::FieldParams&& params) const override; + service::FieldResult>> getArgs( + service::FieldParams&& params) const override; + +private: + const std::shared_ptr _directive; +}; + +} /* namespace graphql::introspection */ + +#endif // INTROSPECTION_H diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 86428af9..a8afb005 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -16,10 +16,24 @@ if(GRAPHQL_UPDATE_SAMPLES) WORKING_DIRECTORY unified COMMENT "Generating mock TodaySchema files") + # unifiedschema_nointrospection + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection) + + add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.cpp + ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.h + COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" --no-introspection + DEPENDS schemagen schema.today.graphql + WORKING_DIRECTORY unified_nointrospection + COMMENT "Generating mock TodaySchema files without Introspection (--no-introspection)") + add_custom_target(unified_schema_files ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.h) + ${CMAKE_CURRENT_BINARY_DIR}/unified/TodaySchema.h + ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.cpp + ${CMAKE_CURRENT_BINARY_DIR}/unified_nointrospection/TodaySchema.h) # separateschema file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/separate) @@ -31,10 +45,22 @@ if(GRAPHQL_UPDATE_SAMPLES) WORKING_DIRECTORY separate COMMENT "Generating mock TodaySchema (--separate-files)") + # separateschema_nointrospection + file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection) + + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection/today_schema_files + COMMAND schemagen --schema="${CMAKE_CURRENT_SOURCE_DIR}/schema.today.graphql" --prefix="Today" --namespace="today" --no-introspection --separate-files > today_schema_files + DEPENDS schemagen schema.today.graphql + WORKING_DIRECTORY separate_nointrospection + COMMENT "Generating mock TodaySchema without Introspection (--no-introspection --separate-files)") + add_custom_target(separate_schema_files ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/separate/today_schema_files) + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/separate/today_schema_files + ${CMAKE_CURRENT_BINARY_DIR}/separate_nointrospection/today_schema_files) - # unifiedschema + # validationschema file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/validation) add_custom_command( @@ -52,15 +78,21 @@ if(GRAPHQL_UPDATE_SAMPLES) ${CMAKE_CURRENT_BINARY_DIR}/validation/ValidationSchema.h) file(GLOB OLD_UNIFIED_FILES ${CMAKE_CURRENT_SOURCE_DIR}/unified/*) + file(GLOB OLD_UNIFIED_NOINTROSPECTION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/unified_nointrospection/*) file(GLOB OLD_SEPARATE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/separate/*) + file(GLOB OLD_SEPARATE_NOINTROSPECTION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/*) file(GLOB OLD_VALIDATION_FILES ${CMAKE_CURRENT_SOURCE_DIR}/validation/ValidationSchema.*) add_custom_command( OUTPUT updated_samples COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_UNIFIED_FILES} COMMAND ${CMAKE_COMMAND} -E copy_directory unified/ ${CMAKE_CURRENT_SOURCE_DIR}/unified/ + COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_UNIFIED_NOINTROSPECTION_FILES} + COMMAND ${CMAKE_COMMAND} -E copy_directory unified_nointrospection/ ${CMAKE_CURRENT_SOURCE_DIR}/unified_nointrospection/ COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_SEPARATE_FILES} COMMAND ${CMAKE_COMMAND} -E copy_directory separate/ ${CMAKE_CURRENT_SOURCE_DIR}/separate/ + COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_SEPARATE_NOINTROSPECTION_FILES} + COMMAND ${CMAKE_COMMAND} -E copy_directory separate_nointrospection/ ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/ COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_VALIDATION_FILES} COMMAND ${CMAKE_COMMAND} -E copy_directory validation/ ${CMAKE_CURRENT_SOURCE_DIR}/validation/ COMMAND ${CMAKE_COMMAND} -E touch updated_samples @@ -76,7 +108,7 @@ if(GRAPHQL_UPDATE_SAMPLES) DEPENDS updated_samples) endif() -# sample +# separateschema set(SEPARATE_SCHEMA_PATHS "") file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/separate/today_schema_files SEPARATE_SCHEMA_FILES) foreach(CPP_FILE IN LISTS SEPARATE_SCHEMA_FILES) @@ -97,11 +129,38 @@ if(GRAPHQL_UPDATE_SAMPLES) add_dependencies(separateschema update_samples) endif() +# separateschema_nointrospection +set(SEPARATE_NOINTROSPECTION_SCHEMA_PATHS "") +file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/today_schema_files SEPARATE_NOINTROSPECTION_SCHEMA_FILES) +foreach(CPP_FILE IN LISTS SEPARATE_NOINTROSPECTION_SCHEMA_FILES) + list(APPEND SEPARATE_NOINTROSPECTION_SCHEMA_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/separate_nointrospection/${CPP_FILE}") +endforeach(CPP_FILE) + +add_library(separateschema_nointrospection STATIC ${SEPARATE_NOINTROSPECTION_SCHEMA_PATHS}) +target_link_libraries(separateschema_nointrospection PUBLIC graphqlservice_nointrospection) +target_compile_definitions(separateschema_nointrospection PUBLIC IMPL_SEPARATE_TODAY) +target_include_directories(separateschema_nointrospection PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include + separate_nointrospection) + +if(GRAPHQL_UPDATE_SAMPLES) + # wait for the sample update to complete + add_dependencies(separateschema_nointrospection update_samples) +endif() + +# separategraphql add_library(separategraphql STATIC today/TodayMock.cpp) target_link_libraries(separategraphql PUBLIC separateschema) -target_compile_definitions(separategraphql PUBLIC IMPL_SEPARATE_TODAY) target_include_directories(separategraphql PUBLIC today) +# separategraphql_nointrospection +add_library(separategraphql_nointrospection STATIC today/TodayMock.cpp) +target_link_libraries(separategraphql_nointrospection PUBLIC separateschema_nointrospection) +target_include_directories(separategraphql_nointrospection PUBLIC today) + +# sample add_executable(sample today/sample.cpp) target_link_libraries(sample PRIVATE separategraphql @@ -111,14 +170,53 @@ target_include_directories(sample PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../include ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) +# sample_nointrospection +add_executable(sample_nointrospection today/sample.cpp) +target_compile_definitions(sample_nointrospection PRIVATE NO_INTROSPECTION) +target_link_libraries(sample_nointrospection PRIVATE + separategraphql_nointrospection + graphqljson) +target_include_directories(sample_nointrospection PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) + if(WIN32 AND BUILD_SHARED_LIBS) - add_custom_target(copy_sample_dlls ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + add_custom_target(copy_sample_dlls ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} DEPENDS graphqlservice graphqljson graphqlpeg graphqlresponse) add_dependencies(sample copy_sample_dlls) + add_dependencies(sample_nointrospection copy_sample_dlls) +endif() + +# benchmark +add_executable(benchmark today/benchmark.cpp) +target_link_libraries(benchmark PRIVATE + separategraphql + graphqljson) +target_include_directories(benchmark PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) + +# benchmark_nointrospection +add_executable(benchmark_nointrospection today/benchmark.cpp) +target_compile_definitions(benchmark_nointrospection PRIVATE NO_INTROSPECTION) +target_link_libraries(benchmark_nointrospection PRIVATE + separategraphql_nointrospection + graphqljson) +target_include_directories(benchmark_nointrospection PRIVATE + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include) + +if(WIN32 AND BUILD_SHARED_LIBS) + add_dependencies(benchmark copy_sample_dlls) + add_dependencies(benchmark_nointrospection copy_sample_dlls) endif() if(GRAPHQL_BUILD_TESTS) @@ -141,6 +239,24 @@ if(GRAPHQL_BUILD_TESTS) target_include_directories(unifiedgraphql PUBLIC today) add_bigobj_flag(unifiedgraphql) + add_library(unifiedschema_nointrospection STATIC unified_nointrospection/TodaySchema.cpp) + target_link_libraries(unifiedschema_nointrospection PUBLIC graphqlservice_nointrospection) + target_include_directories(unifiedschema_nointrospection PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../include + ${CMAKE_CURRENT_SOURCE_DIR}/../PEGTL/include + unified_nointrospection) + + if(GRAPHQL_UPDATE_SAMPLES) + # wait for the sample update to complete + add_dependencies(unifiedschema_nointrospection update_samples) + endif() + + add_library(unifiedgraphql_nointrospection STATIC today/TodayMock.cpp) + target_link_libraries(unifiedgraphql_nointrospection PUBLIC unifiedschema_nointrospection) + target_include_directories(unifiedgraphql_nointrospection PUBLIC today) + add_bigobj_flag(unifiedgraphql_nointrospection) + add_library(validationgraphql STATIC validation/ValidationMock.cpp validation/ValidationSchema.cpp) diff --git a/samples/introspection/IntrospectionSchema.cpp b/samples/introspection/IntrospectionSchema.cpp index 5a578bb4..8621a469 100644 --- a/samples/introspection/IntrospectionSchema.cpp +++ b/samples/introspection/IntrospectionSchema.cpp @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -47,7 +47,7 @@ introspection::TypeKind ModifiedArgument::convert(const } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](introspection::TypeKind&& value, const ResolverParams&) @@ -100,7 +100,7 @@ introspection::DirectiveLocation ModifiedArgument -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](introspection::DirectiveLocation&& value, const ResolverParams&) @@ -132,7 +132,7 @@ Schema::Schema() { } -std::future Schema::resolveTypes(service::ResolverParams&& params) +std::future Schema::resolveTypes(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getTypes(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -141,7 +141,7 @@ std::future Schema::resolveTypes(service::ResolverParams&& para return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Schema::resolveQueryType(service::ResolverParams&& params) +std::future Schema::resolveQueryType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getQueryType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -150,7 +150,7 @@ std::future Schema::resolveQueryType(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Schema::resolveMutationType(service::ResolverParams&& params) +std::future Schema::resolveMutationType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getMutationType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -159,7 +159,7 @@ std::future Schema::resolveMutationType(service::ResolverParams return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Schema::resolveSubscriptionType(service::ResolverParams&& params) +std::future Schema::resolveSubscriptionType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getSubscriptionType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -168,7 +168,7 @@ std::future Schema::resolveSubscriptionType(service::ResolverPa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Schema::resolveDirectives(service::ResolverParams&& params) +std::future Schema::resolveDirectives(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDirectives(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -177,7 +177,7 @@ std::future Schema::resolveDirectives(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Schema::resolve_typename(service::ResolverParams&& params) +std::future Schema::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__Schema)gql" }, std::move(params)); } @@ -200,7 +200,7 @@ Type::Type() { } -std::future Type::resolveKind(service::ResolverParams&& params) +std::future Type::resolveKind(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getKind(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -209,7 +209,7 @@ std::future Type::resolveKind(service::ResolverParams&& params) return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveName(service::ResolverParams&& params) +std::future Type::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -218,7 +218,7 @@ std::future Type::resolveName(service::ResolverParams&& params) return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveDescription(service::ResolverParams&& params) +std::future Type::resolveDescription(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDescription(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -227,7 +227,7 @@ std::future Type::resolveDescription(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveFields(service::ResolverParams&& params) +std::future Type::resolveFields(service::ResolverParams&& params) { const auto defaultArguments = []() { @@ -251,7 +251,7 @@ std::future Type::resolveFields(service::ResolverParams&& param return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveInterfaces(service::ResolverParams&& params) +std::future Type::resolveInterfaces(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getInterfaces(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -260,7 +260,7 @@ std::future Type::resolveInterfaces(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolvePossibleTypes(service::ResolverParams&& params) +std::future Type::resolvePossibleTypes(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPossibleTypes(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -269,7 +269,7 @@ std::future Type::resolvePossibleTypes(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveEnumValues(service::ResolverParams&& params) +std::future Type::resolveEnumValues(service::ResolverParams&& params) { const auto defaultArguments = []() { @@ -293,7 +293,7 @@ std::future Type::resolveEnumValues(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveInputFields(service::ResolverParams&& params) +std::future Type::resolveInputFields(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getInputFields(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -302,7 +302,7 @@ std::future Type::resolveInputFields(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolveOfType(service::ResolverParams&& params) +std::future Type::resolveOfType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getOfType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -311,7 +311,7 @@ std::future Type::resolveOfType(service::ResolverParams&& param return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Type::resolve_typename(service::ResolverParams&& params) +std::future Type::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__Type)gql" }, std::move(params)); } @@ -331,7 +331,7 @@ Field::Field() { } -std::future Field::resolveName(service::ResolverParams&& params) +std::future Field::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -340,7 +340,7 @@ std::future Field::resolveName(service::ResolverParams&& params return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolveDescription(service::ResolverParams&& params) +std::future Field::resolveDescription(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDescription(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -349,7 +349,7 @@ std::future Field::resolveDescription(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolveArgs(service::ResolverParams&& params) +std::future Field::resolveArgs(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getArgs(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -358,7 +358,7 @@ std::future Field::resolveArgs(service::ResolverParams&& params return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolveType(service::ResolverParams&& params) +std::future Field::resolveType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -367,7 +367,7 @@ std::future Field::resolveType(service::ResolverParams&& params return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolveIsDeprecated(service::ResolverParams&& params) +std::future Field::resolveIsDeprecated(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsDeprecated(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -376,7 +376,7 @@ std::future Field::resolveIsDeprecated(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolveDeprecationReason(service::ResolverParams&& params) +std::future Field::resolveDeprecationReason(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDeprecationReason(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -385,7 +385,7 @@ std::future Field::resolveDeprecationReason(service::ResolverPa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Field::resolve_typename(service::ResolverParams&& params) +std::future Field::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__Field)gql" }, std::move(params)); } @@ -403,7 +403,7 @@ InputValue::InputValue() { } -std::future InputValue::resolveName(service::ResolverParams&& params) +std::future InputValue::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -412,7 +412,7 @@ std::future InputValue::resolveName(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future InputValue::resolveDescription(service::ResolverParams&& params) +std::future InputValue::resolveDescription(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDescription(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -421,7 +421,7 @@ std::future InputValue::resolveDescription(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future InputValue::resolveType(service::ResolverParams&& params) +std::future InputValue::resolveType(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getType(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -430,7 +430,7 @@ std::future InputValue::resolveType(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future InputValue::resolveDefaultValue(service::ResolverParams&& params) +std::future InputValue::resolveDefaultValue(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDefaultValue(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -439,7 +439,7 @@ std::future InputValue::resolveDefaultValue(service::ResolverPa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future InputValue::resolve_typename(service::ResolverParams&& params) +std::future InputValue::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__InputValue)gql" }, std::move(params)); } @@ -457,7 +457,7 @@ EnumValue::EnumValue() { } -std::future EnumValue::resolveName(service::ResolverParams&& params) +std::future EnumValue::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -466,7 +466,7 @@ std::future EnumValue::resolveName(service::ResolverParams&& pa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future EnumValue::resolveDescription(service::ResolverParams&& params) +std::future EnumValue::resolveDescription(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDescription(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -475,7 +475,7 @@ std::future EnumValue::resolveDescription(service::ResolverPara return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future EnumValue::resolveIsDeprecated(service::ResolverParams&& params) +std::future EnumValue::resolveIsDeprecated(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsDeprecated(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -484,7 +484,7 @@ std::future EnumValue::resolveIsDeprecated(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future EnumValue::resolveDeprecationReason(service::ResolverParams&& params) +std::future EnumValue::resolveDeprecationReason(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDeprecationReason(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -493,7 +493,7 @@ std::future EnumValue::resolveDeprecationReason(service::Resolv return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future EnumValue::resolve_typename(service::ResolverParams&& params) +std::future EnumValue::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__EnumValue)gql" }, std::move(params)); } @@ -511,7 +511,7 @@ Directive::Directive() { } -std::future Directive::resolveName(service::ResolverParams&& params) +std::future Directive::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -520,7 +520,7 @@ std::future Directive::resolveName(service::ResolverParams&& pa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Directive::resolveDescription(service::ResolverParams&& params) +std::future Directive::resolveDescription(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDescription(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -529,7 +529,7 @@ std::future Directive::resolveDescription(service::ResolverPara return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Directive::resolveLocations(service::ResolverParams&& params) +std::future Directive::resolveLocations(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getLocations(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -538,7 +538,7 @@ std::future Directive::resolveLocations(service::ResolverParams return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Directive::resolveArgs(service::ResolverParams&& params) +std::future Directive::resolveArgs(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getArgs(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -547,137 +547,137 @@ std::future Directive::resolveArgs(service::ResolverParams&& pa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Directive::resolve_typename(service::ResolverParams&& params) +std::future Directive::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(__Directive)gql" }, std::move(params)); } } /* namespace object */ -void AddTypesToSchema(const std::shared_ptr& schema) -{ - schema->AddType("Boolean", std::make_shared("Boolean", R"md(Built-in type)md")); - schema->AddType("Float", std::make_shared("Float", R"md(Built-in type)md")); - schema->AddType("ID", std::make_shared("ID", R"md(Built-in type)md")); - schema->AddType("Int", std::make_shared("Int", R"md(Built-in type)md")); - schema->AddType("String", std::make_shared("String", R"md(Built-in type)md")); - auto typeTypeKind = std::make_shared("__TypeKind", R"md()md"); - schema->AddType("__TypeKind", typeTypeKind); - auto typeDirectiveLocation = std::make_shared("__DirectiveLocation", R"md()md"); - schema->AddType("__DirectiveLocation", typeDirectiveLocation); - auto typeSchema = std::make_shared("__Schema", R"md()md"); - schema->AddType("__Schema", typeSchema); - auto typeType = std::make_shared("__Type", R"md()md"); - schema->AddType("__Type", typeType); - auto typeField = std::make_shared("__Field", R"md()md"); - schema->AddType("__Field", typeField); - auto typeInputValue = std::make_shared("__InputValue", R"md()md"); - schema->AddType("__InputValue", typeInputValue); - auto typeEnumValue = std::make_shared("__EnumValue", R"md()md"); - schema->AddType("__EnumValue", typeEnumValue); - auto typeDirective = std::make_shared("__Directive", R"md()md"); - schema->AddType("__Directive", typeDirective); +void AddTypesToSchema(const std::shared_ptr& schema) +{ + schema->AddType(R"gql(Boolean)gql"sv, schema::ScalarType::Make(R"gql(Boolean)gql"sv, R"md(Built-in type)md")); + schema->AddType(R"gql(Float)gql"sv, schema::ScalarType::Make(R"gql(Float)gql"sv, R"md(Built-in type)md")); + schema->AddType(R"gql(ID)gql"sv, schema::ScalarType::Make(R"gql(ID)gql"sv, R"md(Built-in type)md")); + schema->AddType(R"gql(Int)gql"sv, schema::ScalarType::Make(R"gql(Int)gql"sv, R"md(Built-in type)md")); + schema->AddType(R"gql(String)gql"sv, schema::ScalarType::Make(R"gql(String)gql"sv, R"md(Built-in type)md")); + auto typeTypeKind = schema::EnumType::Make(R"gql(__TypeKind)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__TypeKind)gql"sv, typeTypeKind); + auto typeDirectiveLocation = schema::EnumType::Make(R"gql(__DirectiveLocation)gql"sv, R"md()md"sv); + schema->AddType(R"gql(__DirectiveLocation)gql"sv, typeDirectiveLocation); + auto typeSchema = schema::ObjectType::Make(R"gql(__Schema)gql"sv, R"md()md"); + schema->AddType(R"gql(__Schema)gql"sv, typeSchema); + auto typeType = schema::ObjectType::Make(R"gql(__Type)gql"sv, R"md()md"); + schema->AddType(R"gql(__Type)gql"sv, typeType); + auto typeField = schema::ObjectType::Make(R"gql(__Field)gql"sv, R"md()md"); + schema->AddType(R"gql(__Field)gql"sv, typeField); + auto typeInputValue = schema::ObjectType::Make(R"gql(__InputValue)gql"sv, R"md()md"); + schema->AddType(R"gql(__InputValue)gql"sv, typeInputValue); + auto typeEnumValue = schema::ObjectType::Make(R"gql(__EnumValue)gql"sv, R"md()md"); + schema->AddType(R"gql(__EnumValue)gql"sv, typeEnumValue); + auto typeDirective = schema::ObjectType::Make(R"gql(__Directive)gql"sv, R"md()md"); + schema->AddType(R"gql(__Directive)gql"sv, typeDirective); typeTypeKind->AddEnumValues({ - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::SCALAR)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::OBJECT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::INTERFACE)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::UNION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::ENUM)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::INPUT_OBJECT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::LIST)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTypeKind[static_cast(introspection::TypeKind::NON_NULL)] }, R"md()md", std::nullopt } + { service::s_namesTypeKind[static_cast(introspection::TypeKind::SCALAR)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::INTERFACE)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::UNION)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::ENUM)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::LIST)], R"md()md"sv, std::nullopt }, + { service::s_namesTypeKind[static_cast(introspection::TypeKind::NON_NULL)], R"md()md"sv, std::nullopt } }); typeDirectiveLocation->AddEnumValues({ - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::QUERY)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::MUTATION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SUBSCRIPTION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_DEFINITION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_SPREAD)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INLINE_FRAGMENT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCHEMA)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCALAR)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::OBJECT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD_DEFINITION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ARGUMENT_DEFINITION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INTERFACE)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::UNION)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM_VALUE)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_OBJECT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_FIELD_DEFINITION)] }, R"md()md", std::nullopt } + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::QUERY)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::MUTATION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SUBSCRIPTION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FRAGMENT_SPREAD)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INLINE_FRAGMENT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCHEMA)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::SCALAR)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::FIELD_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ARGUMENT_DEFINITION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INTERFACE)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::UNION)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::ENUM_VALUE)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_OBJECT)], R"md()md"sv, std::nullopt }, + { service::s_namesDirectiveLocation[static_cast(introspection::DirectiveLocation::INPUT_FIELD_DEFINITION)], R"md()md"sv, std::nullopt } }); typeSchema->AddFields({ - std::make_shared("types", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))))), - std::make_shared("queryType", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - std::make_shared("mutationType", R"md()md", std::nullopt, std::vector>(), schema->LookupType("__Type")), - std::make_shared("subscriptionType", R"md()md", std::nullopt, std::vector>(), schema->LookupType("__Type")), - std::make_shared("directives", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Directive"))))) + schema::Field::Make(R"gql(types)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))))), + schema::Field::Make(R"gql(queryType)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), + schema::Field::Make(R"gql(mutationType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")), + schema::Field::Make(R"gql(subscriptionType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")), + schema::Field::Make(R"gql(directives)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Directive"))))) }); typeType->AddFields({ - std::make_shared("kind", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__TypeKind"))), - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("description", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("fields", R"md()md", std::nullopt, std::vector>({ - std::make_shared("includeDeprecated", R"md()md", schema->LookupType("Boolean"), R"gql(false)gql") - }), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Field")))), - std::make_shared("interfaces", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), - std::make_shared("possibleTypes", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), - std::make_shared("enumValues", R"md()md", std::nullopt, std::vector>({ - std::make_shared("includeDeprecated", R"md()md", schema->LookupType("Boolean"), R"gql(false)gql") - }), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__EnumValue")))), - std::make_shared("inputFields", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue")))), - std::make_shared("ofType", R"md()md", std::nullopt, std::vector>(), schema->LookupType("__Type")) + schema::Field::Make(R"gql(kind)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__TypeKind"))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(fields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Field"))), { + schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(false)gql"sv) + }), + schema::Field::Make(R"gql(interfaces)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), + schema::Field::Make(R"gql(possibleTypes)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type")))), + schema::Field::Make(R"gql(enumValues)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__EnumValue"))), { + schema::InputValue::Make(R"gql(includeDeprecated)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(false)gql"sv) + }), + schema::Field::Make(R"gql(inputFields)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue")))), + schema::Field::Make(R"gql(ofType)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("__Type")) }); typeField->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("description", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("args", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))), - std::make_shared("type", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - std::make_shared("isDeprecated", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("deprecationReason", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))), + schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), + schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeInputValue->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("description", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("type", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), - std::make_shared("defaultValue", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(type)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__Type"))), + schema::Field::Make(R"gql(defaultValue)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeEnumValue->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("description", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("isDeprecated", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("deprecationReason", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isDeprecated)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(deprecationReason)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeDirective->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("description", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("locations", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__DirectiveLocation"))))), - std::make_shared("args", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(description)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(locations)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__DirectiveLocation"))))), + schema::Field::Make(R"gql(args)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("__InputValue"))))) }); - schema->AddDirective(std::make_shared("skip", R"md()md", std::vector({ - R"gql(FIELD)gql", - R"gql(FRAGMENT_SPREAD)gql", - R"gql(INLINE_FRAGMENT)gql" - }), std::vector>({ - std::make_shared("if", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("include", R"md()md", std::vector({ - R"gql(FIELD)gql", - R"gql(FRAGMENT_SPREAD)gql", - R"gql(INLINE_FRAGMENT)gql" - }), std::vector>({ - std::make_shared("if", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("deprecated", R"md()md", std::vector({ - R"gql(FIELD_DEFINITION)gql", - R"gql(ENUM_VALUE)gql" - }), std::vector>({ - std::make_shared("reason", R"md()md", schema->LookupType("String"), R"gql("No longer supported")gql") - }))); + schema->AddDirective(schema::Directive::Make(R"gql(skip)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD, + introspection::DirectiveLocation::FRAGMENT_SPREAD, + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(include)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD, + introspection::DirectiveLocation::FRAGMENT_SPREAD, + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(if)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(deprecated)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION, + introspection::DirectiveLocation::ENUM_VALUE + }, { + schema::InputValue::Make(R"gql(reason)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql("No longer supported")gql"sv) + })); } } /* namespace introspection */ diff --git a/samples/introspection/IntrospectionSchema.h b/samples/introspection/IntrospectionSchema.h index 075af537..529e45f1 100644 --- a/samples/introspection/IntrospectionSchema.h +++ b/samples/introspection/IntrospectionSchema.h @@ -6,8 +6,21 @@ #ifndef INTROSPECTIONSCHEMA_H #define INTROSPECTIONSCHEMA_H +#include "graphqlservice/GraphQLSchema.h" #include "graphqlservice/GraphQLService.h" +// clang-format off +#ifdef GRAPHQL_DLLEXPORTS + #ifdef IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllexport) + #else // !IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllimport) + #endif // !IMPL_GRAPHQLINTROSPECTION_DLL +#else // !GRAPHQL_DLLEXPORTS + #define GRAPHQLINTROSPECTION_EXPORT +#endif // !GRAPHQL_DLLEXPORTS +// clang-format on + #include #include #include @@ -15,8 +28,6 @@ namespace graphql { namespace introspection { -class Schema; - enum class TypeKind { SCALAR, @@ -74,13 +85,13 @@ class Schema virtual service::FieldResult>> getDirectives(service::FieldParams&& params) const = 0; private: - std::future resolveTypes(service::ResolverParams&& params); - std::future resolveQueryType(service::ResolverParams&& params); - std::future resolveMutationType(service::ResolverParams&& params); - std::future resolveSubscriptionType(service::ResolverParams&& params); - std::future resolveDirectives(service::ResolverParams&& params); + std::future resolveTypes(service::ResolverParams&& params); + std::future resolveQueryType(service::ResolverParams&& params); + std::future resolveMutationType(service::ResolverParams&& params); + std::future resolveSubscriptionType(service::ResolverParams&& params); + std::future resolveDirectives(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Type @@ -101,17 +112,17 @@ class Type virtual service::FieldResult> getOfType(service::FieldParams&& params) const = 0; private: - std::future resolveKind(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveFields(service::ResolverParams&& params); - std::future resolveInterfaces(service::ResolverParams&& params); - std::future resolvePossibleTypes(service::ResolverParams&& params); - std::future resolveEnumValues(service::ResolverParams&& params); - std::future resolveInputFields(service::ResolverParams&& params); - std::future resolveOfType(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); + std::future resolveKind(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveDescription(service::ResolverParams&& params); + std::future resolveFields(service::ResolverParams&& params); + std::future resolveInterfaces(service::ResolverParams&& params); + std::future resolvePossibleTypes(service::ResolverParams&& params); + std::future resolveEnumValues(service::ResolverParams&& params); + std::future resolveInputFields(service::ResolverParams&& params); + std::future resolveOfType(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); }; class Field @@ -129,14 +140,14 @@ class Field virtual service::FieldResult> getDeprecationReason(service::FieldParams&& params) const = 0; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveArgs(service::ResolverParams&& params); - std::future resolveType(service::ResolverParams&& params); - std::future resolveIsDeprecated(service::ResolverParams&& params); - std::future resolveDeprecationReason(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveDescription(service::ResolverParams&& params); + std::future resolveArgs(service::ResolverParams&& params); + std::future resolveType(service::ResolverParams&& params); + std::future resolveIsDeprecated(service::ResolverParams&& params); + std::future resolveDeprecationReason(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); }; class InputValue @@ -152,12 +163,12 @@ class InputValue virtual service::FieldResult> getDefaultValue(service::FieldParams&& params) const = 0; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveType(service::ResolverParams&& params); - std::future resolveDefaultValue(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveDescription(service::ResolverParams&& params); + std::future resolveType(service::ResolverParams&& params); + std::future resolveDefaultValue(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class EnumValue @@ -173,12 +184,12 @@ class EnumValue virtual service::FieldResult> getDeprecationReason(service::FieldParams&& params) const = 0; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveIsDeprecated(service::ResolverParams&& params); - std::future resolveDeprecationReason(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveDescription(service::ResolverParams&& params); + std::future resolveIsDeprecated(service::ResolverParams&& params); + std::future resolveDeprecationReason(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Directive @@ -194,17 +205,17 @@ class Directive virtual service::FieldResult>> getArgs(service::FieldParams&& params) const = 0; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveDescription(service::ResolverParams&& params); - std::future resolveLocations(service::ResolverParams&& params); - std::future resolveArgs(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveDescription(service::ResolverParams&& params); + std::future resolveLocations(service::ResolverParams&& params); + std::future resolveArgs(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace object */ -GRAPHQLSERVICE_EXPORT void AddTypesToSchema(const std::shared_ptr& schema); +GRAPHQLINTROSPECTION_EXPORT void AddTypesToSchema(const std::shared_ptr& schema); } /* namespace introspection */ } /* namespace graphql */ diff --git a/samples/schema.today.graphql b/samples/schema.today.graphql index 6fdeaa77..17052dac 100644 --- a/samples/schema.today.graphql +++ b/samples/schema.today.graphql @@ -115,6 +115,7 @@ type Appointment implements Node { when: DateTime subject: String isNow: Boolean! + forceError: String } type Task implements Node { diff --git a/samples/separate/AppointmentConnectionObject.cpp b/samples/separate/AppointmentConnectionObject.cpp index 5d9f852d..771705e6 100644 --- a/samples/separate/AppointmentConnectionObject.cpp +++ b/samples/separate/AppointmentConnectionObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> AppointmentConnection::getPageIn throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); } -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) +std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult> throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); } -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) +std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future AppointmentConnection::resolveEdges(service::Resolv return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) +std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); } } /* namespace object */ -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema) +void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema) { typeAppointmentConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) }); } diff --git a/samples/separate/AppointmentConnectionObject.h b/samples/separate/AppointmentConnectionObject.h index b644375e..a2086518 100644 --- a/samples/separate/AppointmentConnectionObject.h +++ b/samples/separate/AppointmentConnectionObject.h @@ -21,10 +21,10 @@ class AppointmentConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/AppointmentEdgeObject.cpp b/samples/separate/AppointmentEdgeObject.cpp index 8e1e74a0..4bb5979d 100644 --- a/samples/separate/AppointmentEdgeObject.cpp +++ b/samples/separate/AppointmentEdgeObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> AppointmentEdge::getNode(serv throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); } -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) +std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult AppointmentEdge::getCursor(service::FieldP throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); } -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) +std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future AppointmentEdge::resolveCursor(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) +std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); } } /* namespace object */ -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema) +void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema) { typeAppointmentEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Appointment")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); } diff --git a/samples/separate/AppointmentEdgeObject.h b/samples/separate/AppointmentEdgeObject.h index 1657480c..454cd0d1 100644 --- a/samples/separate/AppointmentEdgeObject.h +++ b/samples/separate/AppointmentEdgeObject.h @@ -21,10 +21,10 @@ class AppointmentEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/AppointmentObject.cpp b/samples/separate/AppointmentObject.cpp index 1fcb5663..a1f68a6d 100644 --- a/samples/separate/AppointmentObject.cpp +++ b/samples/separate/AppointmentObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -23,6 +23,7 @@ Appointment::Appointment() "Appointment" }, { { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } }, { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, @@ -36,7 +37,7 @@ service::FieldResult Appointment::getId(service::FieldParams&& throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); } -std::future Appointment::resolveId(service::ResolverParams&& params) +std::future Appointment::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -50,7 +51,7 @@ service::FieldResult> Appointment::getWhen(servic throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); } -std::future Appointment::resolveWhen(service::ResolverParams&& params) +std::future Appointment::resolveWhen(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getWhen(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -64,7 +65,7 @@ service::FieldResult> Appointment::getSubjec throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); } -std::future Appointment::resolveSubject(service::ResolverParams&& params) +std::future Appointment::resolveSubject(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getSubject(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -78,7 +79,7 @@ service::FieldResult Appointment::getIsNow(service::Field throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); } -std::future Appointment::resolveIsNow(service::ResolverParams&& params) +std::future Appointment::resolveIsNow(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsNow(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -87,23 +88,38 @@ std::future Appointment::resolveIsNow(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Appointment::resolve_typename(service::ResolverParams&& params) +service::FieldResult> Appointment::getForceError(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); +} + +std::future Appointment::resolveForceError(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getForceError(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Appointment::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); } } /* namespace object */ -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema) +void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema) { typeAppointment->AddInterfaces({ - std::static_pointer_cast(schema->LookupType("Node")) + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) }); typeAppointment->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("when", R"md()md", std::nullopt, std::vector>(), schema->LookupType("DateTime")), - std::make_shared("subject", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("isNow", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); } diff --git a/samples/separate/AppointmentObject.h b/samples/separate/AppointmentObject.h index 7fd5a3ff..6ebc29d2 100644 --- a/samples/separate/AppointmentObject.h +++ b/samples/separate/AppointmentObject.h @@ -22,14 +22,16 @@ class Appointment virtual service::FieldResult> getWhen(service::FieldParams&& params) const; virtual service::FieldResult> getSubject(service::FieldParams&& params) const; virtual service::FieldResult getIsNow(service::FieldParams&& params) const; + virtual service::FieldResult> getForceError(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveWhen(service::ResolverParams&& params); + std::future resolveSubject(service::ResolverParams&& params); + std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveForceError(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/CompleteTaskPayloadObject.cpp b/samples/separate/CompleteTaskPayloadObject.cpp index 2c88956e..1f010b75 100644 --- a/samples/separate/CompleteTaskPayloadObject.cpp +++ b/samples/separate/CompleteTaskPayloadObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> CompleteTaskPayload::getTask(service throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); } -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getTask(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult> CompleteTaskPayload::g throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); } -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getClientMutationId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future CompleteTaskPayload::resolveClientMutationId(servic return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); } } /* namespace object */ -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema) +void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema) { typeCompleteTaskPayload->AddFields({ - std::make_shared("task", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Task")), - std::make_shared("clientMutationId", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); } diff --git a/samples/separate/CompleteTaskPayloadObject.h b/samples/separate/CompleteTaskPayloadObject.h index 5144ca8a..8d7a122b 100644 --- a/samples/separate/CompleteTaskPayloadObject.h +++ b/samples/separate/CompleteTaskPayloadObject.h @@ -21,10 +21,10 @@ class CompleteTaskPayload virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); + std::future resolveTask(service::ResolverParams&& params); + std::future resolveClientMutationId(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/ExpensiveObject.cpp b/samples/separate/ExpensiveObject.cpp index 91700b5c..728081f4 100644 --- a/samples/separate/ExpensiveObject.cpp +++ b/samples/separate/ExpensiveObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -31,7 +31,7 @@ service::FieldResult Expensive::getOrder(service::FieldParams throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); } -std::future Expensive::resolveOrder(service::ResolverParams&& params) +std::future Expensive::resolveOrder(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getOrder(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -40,17 +40,17 @@ std::future Expensive::resolveOrder(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Expensive::resolve_typename(service::ResolverParams&& params) +std::future Expensive::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); } } /* namespace object */ -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema) +void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema) { typeExpensive->AddFields({ - std::make_shared("order", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) }); } diff --git a/samples/separate/ExpensiveObject.h b/samples/separate/ExpensiveObject.h index 33585097..a435994a 100644 --- a/samples/separate/ExpensiveObject.h +++ b/samples/separate/ExpensiveObject.h @@ -20,9 +20,9 @@ class Expensive virtual service::FieldResult getOrder(service::FieldParams&& params) const; private: - std::future resolveOrder(service::ResolverParams&& params); + std::future resolveOrder(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/FolderConnectionObject.cpp b/samples/separate/FolderConnectionObject.cpp index 82c0781e..d08718c8 100644 --- a/samples/separate/FolderConnectionObject.cpp +++ b/samples/separate/FolderConnectionObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> FolderConnection::getPageInfo(se throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); } -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) +std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult>>> Fo throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); } -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) +std::future FolderConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future FolderConnection::resolveEdges(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) +std::future FolderConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); } } /* namespace object */ -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema) +void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema) { typeFolderConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) }); } diff --git a/samples/separate/FolderConnectionObject.h b/samples/separate/FolderConnectionObject.h index f62ca592..9bcd2d4a 100644 --- a/samples/separate/FolderConnectionObject.h +++ b/samples/separate/FolderConnectionObject.h @@ -21,10 +21,10 @@ class FolderConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/FolderEdgeObject.cpp b/samples/separate/FolderEdgeObject.cpp index fb67ae0b..0c8ba56b 100644 --- a/samples/separate/FolderEdgeObject.cpp +++ b/samples/separate/FolderEdgeObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> FolderEdge::getNode(service::Field throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); } -std::future FolderEdge::resolveNode(service::ResolverParams&& params) +std::future FolderEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult FolderEdge::getCursor(service::FieldParams throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); } -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) +std::future FolderEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future FolderEdge::resolveCursor(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) +std::future FolderEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); } } /* namespace object */ -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema) +void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema) { typeFolderEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Folder")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); } diff --git a/samples/separate/FolderEdgeObject.h b/samples/separate/FolderEdgeObject.h index 5f7cdd53..4fc210d2 100644 --- a/samples/separate/FolderEdgeObject.h +++ b/samples/separate/FolderEdgeObject.h @@ -21,10 +21,10 @@ class FolderEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/FolderObject.cpp b/samples/separate/FolderObject.cpp index eaed083f..8cfbe7c0 100644 --- a/samples/separate/FolderObject.cpp +++ b/samples/separate/FolderObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -35,7 +35,7 @@ service::FieldResult Folder::getId(service::FieldParams&&) con throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); } -std::future Folder::resolveId(service::ResolverParams&& params) +std::future Folder::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -49,7 +49,7 @@ service::FieldResult> Folder::getName(servic throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); } -std::future Folder::resolveName(service::ResolverParams&& params) +std::future Folder::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -63,7 +63,7 @@ service::FieldResult Folder::getUnreadCount(service::FieldPar throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); } -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) +std::future Folder::resolveUnreadCount(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getUnreadCount(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -72,22 +72,22 @@ std::future Folder::resolveUnreadCount(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Folder::resolve_typename(service::ResolverParams&& params) +std::future Folder::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); } } /* namespace object */ -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema) +void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema) { typeFolder->AddInterfaces({ - std::static_pointer_cast(schema->LookupType("Node")) + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) }); typeFolder->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("unreadCount", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) }); } diff --git a/samples/separate/FolderObject.h b/samples/separate/FolderObject.h index d956b051..13fd2c61 100644 --- a/samples/separate/FolderObject.h +++ b/samples/separate/FolderObject.h @@ -23,11 +23,11 @@ class Folder virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveUnreadCount(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/MutationObject.cpp b/samples/separate/MutationObject.cpp index 349043d7..ff147f37 100644 --- a/samples/separate/MutationObject.cpp +++ b/samples/separate/MutationObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> Mutation::applyComple throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); } -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) +std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) { auto argInput = service::ModifiedArgument::require("input", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -47,7 +47,7 @@ service::FieldResult Mutation::applySetFloat(service::Field throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); } -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) +std::future Mutation::resolveSetFloat(service::ResolverParams&& params) { auto argValue = service::ModifiedArgument::require("value", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -57,22 +57,22 @@ std::future Mutation::resolveSetFloat(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Mutation::resolve_typename(service::ResolverParams&& params) +std::future Mutation::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); } } /* namespace object */ -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) +void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) { typeMutation->AddFields({ - std::make_shared("completeTask", R"md()md", std::nullopt, std::vector>({ - std::make_shared("input", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload"))), - std::make_shared("setFloat", R"md()md", std::nullopt, std::vector>({ - std::make_shared("value", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float"))) + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) + }) }); } diff --git a/samples/separate/MutationObject.h b/samples/separate/MutationObject.h index 7a90870e..fcb6340f 100644 --- a/samples/separate/MutationObject.h +++ b/samples/separate/MutationObject.h @@ -21,10 +21,10 @@ class Mutation virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); + std::future resolveCompleteTask(service::ResolverParams&& params); + std::future resolveSetFloat(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/NestedTypeObject.cpp b/samples/separate/NestedTypeObject.cpp index bb63d848..317cc8e4 100644 --- a/samples/separate/NestedTypeObject.cpp +++ b/samples/separate/NestedTypeObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult NestedType::getDepth(service::FieldParam throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); } -std::future NestedType::resolveDepth(service::ResolverParams&& params) +std::future NestedType::resolveDepth(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDepth(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult> NestedType::getNested(service: throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); } -std::future NestedType::resolveNested(service::ResolverParams&& params) +std::future NestedType::resolveNested(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future NestedType::resolveNested(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future NestedType::resolve_typename(service::ResolverParams&& params) +std::future NestedType::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); } } /* namespace object */ -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema) +void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema) { typeNestedType->AddFields({ - std::make_shared("depth", R"md(Depth of the nested element)md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - std::make_shared("nested", R"md(Link to the next level)md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) + schema::Field::Make(R"gql(depth)gql"sv, R"md(Depth of the nested element)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), + schema::Field::Make(R"gql(nested)gql"sv, R"md(Link to the next level)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) }); } diff --git a/samples/separate/NestedTypeObject.h b/samples/separate/NestedTypeObject.h index 6d983448..8fa86966 100644 --- a/samples/separate/NestedTypeObject.h +++ b/samples/separate/NestedTypeObject.h @@ -21,10 +21,10 @@ class NestedType virtual service::FieldResult> getNested(service::FieldParams&& params) const; private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); + std::future resolveDepth(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/PageInfoObject.cpp b/samples/separate/PageInfoObject.cpp index d0d0d1d7..eea08374 100644 --- a/samples/separate/PageInfoObject.cpp +++ b/samples/separate/PageInfoObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult PageInfo::getHasNextPage(service::Fi throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); } -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) +std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHasNextPage(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult PageInfo::getHasPreviousPage(service throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); } -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) +std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHasPreviousPage(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future PageInfo::resolveHasPreviousPage(service::ResolverP return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future PageInfo::resolve_typename(service::ResolverParams&& params) +std::future PageInfo::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); } } /* namespace object */ -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema) +void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema) { typePageInfo->AddFields({ - std::make_shared("hasNextPage", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("hasPreviousPage", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) }); } diff --git a/samples/separate/PageInfoObject.h b/samples/separate/PageInfoObject.h index 691b8980..ca0108ab 100644 --- a/samples/separate/PageInfoObject.h +++ b/samples/separate/PageInfoObject.h @@ -21,10 +21,10 @@ class PageInfo virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); + std::future resolveHasNextPage(service::ResolverParams&& params); + std::future resolveHasPreviousPage(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/QueryObject.cpp b/samples/separate/QueryObject.cpp index 0a7f88bb..44e97702 100644 --- a/samples/separate/QueryObject.cpp +++ b/samples/separate/QueryObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -34,10 +34,8 @@ Query::Query() { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } }) - , _schema(std::make_shared()) + , _schema(GetSchema()) { - introspection::AddTypesToSchema(_schema); - today::AddTypesToSchema(_schema); } service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const @@ -45,7 +43,7 @@ service::FieldResult> Query::getNode(service::F throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); } -std::future Query::resolveNode(service::ResolverParams&& params) +std::future Query::resolveNode(service::ResolverParams&& params) { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -60,7 +58,7 @@ service::FieldResult> Query::getAppointme throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); } -std::future Query::resolveAppointments(service::ResolverParams&& params) +std::future Query::resolveAppointments(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -78,7 +76,7 @@ service::FieldResult> Query::getTasks(service::F throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); } -std::future Query::resolveTasks(service::ResolverParams&& params) +std::future Query::resolveTasks(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -96,7 +94,7 @@ service::FieldResult> Query::getUnreadCounts(s throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); } -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) +std::future Query::resolveUnreadCounts(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -114,7 +112,7 @@ service::FieldResult>> Query::getAppoin throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); } -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +std::future Query::resolveAppointmentsById(service::ResolverParams&& params) { const auto defaultArguments = []() { @@ -151,7 +149,7 @@ service::FieldResult>> Query::getTasksById(ser throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); } -std::future Query::resolveTasksById(service::ResolverParams&& params) +std::future Query::resolveTasksById(service::ResolverParams&& params) { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -166,7 +164,7 @@ service::FieldResult>> Query::getUnreadCount throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); } -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -181,7 +179,7 @@ service::FieldResult> Query::getNested(service::Fiel throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); } -std::future Query::resolveNested(service::ResolverParams&& params) +std::future Query::resolveNested(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -195,7 +193,7 @@ service::FieldResult Query::getUnimplemented(service::Fiel throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); } -std::future Query::resolveUnimplemented(service::ResolverParams&& params) +std::future Query::resolveUnimplemented(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getUnimplemented(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -209,7 +207,7 @@ service::FieldResult>> Query::getExpensiv throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); } -std::future Query::resolveExpensive(service::ResolverParams&& params) +std::future Query::resolveExpensive(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getExpensive(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -218,61 +216,63 @@ std::future Query::resolveExpensive(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolve_typename(service::ResolverParams&& params) +std::future Query::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); } -std::future Query::resolve_schema(service::ResolverParams&& params) +std::future Query::resolve_schema(service::ResolverParams&& params) { - return service::ModifiedResult::convert(std::static_pointer_cast(_schema), std::move(params)); + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); } -std::future Query::resolve_type(service::ResolverParams&& params) +std::future Query::resolve_type(service::ResolverParams&& params) { auto argName = service::ModifiedArgument::require("name", params.arguments); + const auto& baseType = _schema->LookupType(argName); + std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - return service::ModifiedResult::convert(_schema->LookupType(argName), std::move(params)); + return service::ModifiedResult::convert(result, std::move(params)); } } /* namespace object */ -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) +void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) { typeQuery->AddFields({ - std::make_shared("node", R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md", std::nullopt, std::vector>({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql") - }), schema->LookupType("Node")), - std::make_shared("appointments", R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection"))), - std::make_shared("tasks", R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection"))), - std::make_shared("unreadCounts", R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection"))), - std::make_shared("appointmentsById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment")))), - std::make_shared("tasksById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task")))), - std::make_shared("unreadCountsById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder")))), - std::make_shared("nested", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - std::make_shared("unimplemented", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("expensive", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) + schema::Field::Make(R"gql(node)gql"sv, R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md"sv, std::nullopt, schema->LookupType("Node"), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointments)gql"sv, R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(tasks)gql"sv, R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + }), + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) }); } diff --git a/samples/separate/QueryObject.h b/samples/separate/QueryObject.h index f24bb5da..71cae0b8 100644 --- a/samples/separate/QueryObject.h +++ b/samples/separate/QueryObject.h @@ -29,22 +29,22 @@ class Query virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; + std::future resolveNode(service::ResolverParams&& params); + std::future resolveAppointments(service::ResolverParams&& params); + std::future resolveTasks(service::ResolverParams&& params); + std::future resolveUnreadCounts(service::ResolverParams&& params); + std::future resolveAppointmentsById(service::ResolverParams&& params); + std::future resolveTasksById(service::ResolverParams&& params); + std::future resolveUnreadCountsById(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + std::future resolveUnimplemented(service::ResolverParams&& params); + std::future resolveExpensive(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_schema(service::ResolverParams&& params); + std::future resolve_type(service::ResolverParams&& params); + + std::shared_ptr _schema; }; } /* namespace graphql::today::object */ diff --git a/samples/separate/SubscriptionObject.cpp b/samples/separate/SubscriptionObject.cpp index 3c2d9eb5..1bb97a36 100644 --- a/samples/separate/SubscriptionObject.cpp +++ b/samples/separate/SubscriptionObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> Subscription::getNextAppointm throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); } -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) +std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNextAppointmentChange(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult> Subscription::getNodeChan throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); } -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) +std::future Subscription::resolveNodeChange(service::ResolverParams&& params) { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -56,20 +56,20 @@ std::future Subscription::resolveNodeChange(service::ResolverPa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Subscription::resolve_typename(service::ResolverParams&& params) +std::future Subscription::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); } } /* namespace object */ -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema) +void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema) { typeSubscription->AddFields({ - std::make_shared("nextAppointmentChange", R"md()md", std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"), std::vector>(), schema->LookupType("Appointment")), - std::make_shared("nodeChange", R"md()md", std::nullopt, std::vector>({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node"))) + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }) }); } diff --git a/samples/separate/SubscriptionObject.h b/samples/separate/SubscriptionObject.h index c94a9025..6696710a 100644 --- a/samples/separate/SubscriptionObject.h +++ b/samples/separate/SubscriptionObject.h @@ -21,10 +21,10 @@ class Subscription virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); + std::future resolveNextAppointmentChange(service::ResolverParams&& params); + std::future resolveNodeChange(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/TaskConnectionObject.cpp b/samples/separate/TaskConnectionObject.cpp index 7cc896bd..cb744845 100644 --- a/samples/separate/TaskConnectionObject.cpp +++ b/samples/separate/TaskConnectionObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> TaskConnection::getPageInfo(serv throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); } -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) +std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult>>> Task throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); } -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) +std::future TaskConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future TaskConnection::resolveEdges(service::ResolverParam return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) +std::future TaskConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); } } /* namespace object */ -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema) +void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema) { typeTaskConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) }); } diff --git a/samples/separate/TaskConnectionObject.h b/samples/separate/TaskConnectionObject.h index f60c2eba..3b27f775 100644 --- a/samples/separate/TaskConnectionObject.h +++ b/samples/separate/TaskConnectionObject.h @@ -21,10 +21,10 @@ class TaskConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/TaskEdgeObject.cpp b/samples/separate/TaskEdgeObject.cpp index 7f2a9607..adbe7362 100644 --- a/samples/separate/TaskEdgeObject.cpp +++ b/samples/separate/TaskEdgeObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -32,7 +32,7 @@ service::FieldResult> TaskEdge::getNode(service::FieldPara throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); } -std::future TaskEdge::resolveNode(service::ResolverParams&& params) +std::future TaskEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -46,7 +46,7 @@ service::FieldResult TaskEdge::getCursor(service::FieldParams&& throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); } -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) +std::future TaskEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -55,18 +55,18 @@ std::future TaskEdge::resolveCursor(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) +std::future TaskEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); } } /* namespace object */ -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema) +void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema) { typeTaskEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Task")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); } diff --git a/samples/separate/TaskEdgeObject.h b/samples/separate/TaskEdgeObject.h index 0b8d3d5d..27b60417 100644 --- a/samples/separate/TaskEdgeObject.h +++ b/samples/separate/TaskEdgeObject.h @@ -21,10 +21,10 @@ class TaskEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/TaskObject.cpp b/samples/separate/TaskObject.cpp index c86bc27a..f766136f 100644 --- a/samples/separate/TaskObject.cpp +++ b/samples/separate/TaskObject.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -35,7 +35,7 @@ service::FieldResult Task::getId(service::FieldParams&&) const throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); } -std::future Task::resolveId(service::ResolverParams&& params) +std::future Task::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -49,7 +49,7 @@ service::FieldResult> Task::getTitle(service throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); } -std::future Task::resolveTitle(service::ResolverParams&& params) +std::future Task::resolveTitle(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getTitle(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -63,7 +63,7 @@ service::FieldResult Task::getIsComplete(service::FieldPa throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); } -std::future Task::resolveIsComplete(service::ResolverParams&& params) +std::future Task::resolveIsComplete(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsComplete(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -72,22 +72,22 @@ std::future Task::resolveIsComplete(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolve_typename(service::ResolverParams&& params) +std::future Task::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); } } /* namespace object */ -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema) +void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema) { typeTask->AddInterfaces({ - std::static_pointer_cast(schema->LookupType("Node")) + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) }); typeTask->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("title", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("isComplete", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) }); } diff --git a/samples/separate/TaskObject.h b/samples/separate/TaskObject.h index 7bf6f576..a6652cca 100644 --- a/samples/separate/TaskObject.h +++ b/samples/separate/TaskObject.h @@ -23,11 +23,11 @@ class Task virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveTitle(service::ResolverParams&& params); + std::future resolveIsComplete(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace graphql::today::object */ diff --git a/samples/separate/TodaySchema.cpp b/samples/separate/TodaySchema.cpp index 4eddca98..462e8845 100644 --- a/samples/separate/TodaySchema.cpp +++ b/samples/separate/TodaySchema.cpp @@ -3,7 +3,7 @@ #include "TodayObjects.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -45,7 +45,7 @@ today::TaskState ModifiedArgument::convert(const response::Val } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](today::TaskState&& value, const ResolverParams&) @@ -95,79 +95,79 @@ Operations::Operations(std::shared_ptr query, std::shared_ptr& schema) +void AddTypesToSchema(const std::shared_ptr& schema) { - schema->AddType("ItemCursor", std::make_shared("ItemCursor", R"md()md")); - schema->AddType("DateTime", std::make_shared("DateTime", R"md()md")); - auto typeTaskState = std::make_shared("TaskState", R"md()md"); - schema->AddType("TaskState", typeTaskState); - auto typeCompleteTaskInput = std::make_shared("CompleteTaskInput", R"md()md"); - schema->AddType("CompleteTaskInput", typeCompleteTaskInput); - auto typeUnionType = std::make_shared("UnionType", R"md()md"); - schema->AddType("UnionType", typeUnionType); - auto typeNode = std::make_shared("Node", R"md(Node interface for Relay support)md"); - schema->AddType("Node", typeNode); - auto typeQuery = std::make_shared("Query", R"md(Root Query type)md"); - schema->AddType("Query", typeQuery); - auto typePageInfo = std::make_shared("PageInfo", R"md()md"); - schema->AddType("PageInfo", typePageInfo); - auto typeAppointmentEdge = std::make_shared("AppointmentEdge", R"md()md"); - schema->AddType("AppointmentEdge", typeAppointmentEdge); - auto typeAppointmentConnection = std::make_shared("AppointmentConnection", R"md()md"); - schema->AddType("AppointmentConnection", typeAppointmentConnection); - auto typeTaskEdge = std::make_shared("TaskEdge", R"md()md"); - schema->AddType("TaskEdge", typeTaskEdge); - auto typeTaskConnection = std::make_shared("TaskConnection", R"md()md"); - schema->AddType("TaskConnection", typeTaskConnection); - auto typeFolderEdge = std::make_shared("FolderEdge", R"md()md"); - schema->AddType("FolderEdge", typeFolderEdge); - auto typeFolderConnection = std::make_shared("FolderConnection", R"md()md"); - schema->AddType("FolderConnection", typeFolderConnection); - auto typeCompleteTaskPayload = std::make_shared("CompleteTaskPayload", R"md()md"); - schema->AddType("CompleteTaskPayload", typeCompleteTaskPayload); - auto typeMutation = std::make_shared("Mutation", R"md()md"); - schema->AddType("Mutation", typeMutation); - auto typeSubscription = std::make_shared("Subscription", R"md()md"); - schema->AddType("Subscription", typeSubscription); - auto typeAppointment = std::make_shared("Appointment", R"md()md"); - schema->AddType("Appointment", typeAppointment); - auto typeTask = std::make_shared("Task", R"md()md"); - schema->AddType("Task", typeTask); - auto typeFolder = std::make_shared("Folder", R"md()md"); - schema->AddType("Folder", typeFolder); - auto typeNestedType = std::make_shared("NestedType", R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); - schema->AddType("NestedType", typeNestedType); - auto typeExpensive = std::make_shared("Expensive", R"md()md"); - schema->AddType("Expensive", typeExpensive); + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); + schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); + auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md(Node interface for Relay support)md"sv); + schema->AddType(R"gql(Node)gql"sv, typeNode); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(Root Query type)md"); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + schema->AddType(R"gql(Task)gql"sv, typeTask); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + schema->AddType(R"gql(Folder)gql"sv, typeFolder); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); + schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); typeTaskState->AddEnumValues({ - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::New)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Started)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Complete)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Unassigned)] }, R"md()md", std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md") } + { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv) } }); typeCompleteTaskInput->AddInputValues({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"), - std::make_shared("isComplete", R"md()md", schema->LookupType("Boolean"), R"gql(true)gql"), - std::make_shared("clientMutationId", R"md()md", schema->LookupType("String"), R"gql()gql") + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) }); typeUnionType->AddPossibleTypes({ - schema->LookupType("Appointment"), - schema->LookupType("Task"), - schema->LookupType("Folder") + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) }); typeNode->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) }); AddQueryDetails(typeQuery, schema); @@ -187,44 +187,60 @@ void AddTypesToSchema(const std::shared_ptr& schema) AddNestedTypeDetails(typeNestedType, schema); AddExpensiveDetails(typeExpensive, schema); - schema->AddDirective(std::make_shared("id", R"md()md", std::vector({ - R"gql(FIELD_DEFINITION)gql" - }), std::vector>())); - schema->AddDirective(std::make_shared("subscriptionTag", R"md()md", std::vector({ - R"gql(SUBSCRIPTION)gql" - }), std::vector>({ - std::make_shared("field", R"md()md", schema->LookupType("String"), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("queryTag", R"md()md", std::vector({ - R"gql(QUERY)gql" - }), std::vector>({ - std::make_shared("query", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fieldTag", R"md()md", std::vector({ - R"gql(FIELD)gql" - }), std::vector>({ - std::make_shared("field", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fragmentDefinitionTag", R"md()md", std::vector({ - R"gql(FRAGMENT_DEFINITION)gql" - }), std::vector>({ - std::make_shared("fragmentDefinition", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fragmentSpreadTag", R"md()md", std::vector({ - R"gql(FRAGMENT_SPREAD)gql" - }), std::vector>({ - std::make_shared("fragmentSpread", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("inlineFragmentTag", R"md()md", std::vector({ - R"gql(INLINE_FRAGMENT)gql" - }), std::vector>({ - std::make_shared("inlineFragment", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); + schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION + })); + schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::SUBSCRIPTION + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::QUERY + }, { + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_DEFINITION + }, { + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_SPREAD + }, { + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); schema->AddQueryType(typeQuery); schema->AddMutationType(typeMutation); schema->AddSubscriptionType(typeSubscription); } +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(false); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + } /* namespace today */ } /* namespace graphql */ diff --git a/samples/separate/TodaySchema.h b/samples/separate/TodaySchema.h index 5a948be1..11a78db8 100644 --- a/samples/separate/TodaySchema.h +++ b/samples/separate/TodaySchema.h @@ -6,6 +6,7 @@ #ifndef TODAYSCHEMA_H #define TODAYSCHEMA_H +#include "graphqlservice/GraphQLSchema.h" #include "graphqlservice/GraphQLService.h" #include @@ -13,13 +14,6 @@ #include namespace graphql { -namespace introspection { - -class Schema; -class ObjectType; - -} /* namespace introspection */ - namespace today { enum class TaskState @@ -75,24 +69,24 @@ class Operations std::shared_ptr _subscription; }; -void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); -void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema); -void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema); -void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema); -void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema); -void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema); -void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema); -void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema); -void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema); -void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); -void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema); -void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema); -void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema); -void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema); -void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema); -void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema); - -void AddTypesToSchema(const std::shared_ptr& schema); +void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); +void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema); +void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema); +void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema); +void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema); +void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema); +void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema); +void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema); +void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema); +void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); +void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema); +void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema); +void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema); +void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema); +void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema); +void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); } /* namespace today */ } /* namespace graphql */ diff --git a/samples/separate_nointrospection/AppointmentConnectionObject.cpp b/samples/separate_nointrospection/AppointmentConnectionObject.cpp new file mode 100644 index 00000000..771705e6 --- /dev/null +++ b/samples/separate_nointrospection/AppointmentConnectionObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentConnection::AppointmentConnection() + : service::Object({ + "AppointmentConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); +} + +std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); +} + +std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema) +{ + typeAppointmentConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/AppointmentConnectionObject.h b/samples/separate_nointrospection/AppointmentConnectionObject.h new file mode 100644 index 00000000..a2086518 --- /dev/null +++ b/samples/separate_nointrospection/AppointmentConnectionObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef APPOINTMENTCONNECTIONOBJECT_H +#define APPOINTMENTCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class AppointmentConnection + : public service::Object +{ +protected: + explicit AppointmentConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // APPOINTMENTCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/AppointmentEdgeObject.cpp b/samples/separate_nointrospection/AppointmentEdgeObject.cpp new file mode 100644 index 00000000..4bb5979d --- /dev/null +++ b/samples/separate_nointrospection/AppointmentEdgeObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +AppointmentEdge::AppointmentEdge() + : service::Object({ + "AppointmentEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); +} + +std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); +} + +std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema) +{ + typeAppointmentEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/AppointmentEdgeObject.h b/samples/separate_nointrospection/AppointmentEdgeObject.h new file mode 100644 index 00000000..454cd0d1 --- /dev/null +++ b/samples/separate_nointrospection/AppointmentEdgeObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef APPOINTMENTEDGEOBJECT_H +#define APPOINTMENTEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class AppointmentEdge + : public service::Object +{ +protected: + explicit AppointmentEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // APPOINTMENTEDGEOBJECT_H diff --git a/samples/separate_nointrospection/AppointmentObject.cpp b/samples/separate_nointrospection/AppointmentObject.cpp new file mode 100644 index 00000000..a1f68a6d --- /dev/null +++ b/samples/separate_nointrospection/AppointmentObject.cpp @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Appointment::Appointment() + : service::Object({ + "Node", + "UnionType", + "Appointment" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, + { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, + { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } } + }) +{ +} + +service::FieldResult Appointment::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); +} + +std::future Appointment::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getWhen(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); +} + +std::future Appointment::resolveWhen(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getWhen(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getSubject(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); +} + +std::future Appointment::resolveSubject(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getSubject(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Appointment::getIsNow(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); +} + +std::future Appointment::resolveIsNow(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getIsNow(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getForceError(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); +} + +std::future Appointment::resolveForceError(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getForceError(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Appointment::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema) +{ + typeAppointment->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeAppointment->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/AppointmentObject.h b/samples/separate_nointrospection/AppointmentObject.h new file mode 100644 index 00000000..6ebc29d2 --- /dev/null +++ b/samples/separate_nointrospection/AppointmentObject.h @@ -0,0 +1,39 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef APPOINTMENTOBJECT_H +#define APPOINTMENTOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Appointment + : public service::Object + , public Node +{ +protected: + explicit Appointment(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getWhen(service::FieldParams&& params) const; + virtual service::FieldResult> getSubject(service::FieldParams&& params) const; + virtual service::FieldResult getIsNow(service::FieldParams&& params) const; + virtual service::FieldResult> getForceError(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveWhen(service::ResolverParams&& params); + std::future resolveSubject(service::ResolverParams&& params); + std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveForceError(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // APPOINTMENTOBJECT_H diff --git a/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp b/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp new file mode 100644 index 00000000..1f010b75 --- /dev/null +++ b/samples/separate_nointrospection/CompleteTaskPayloadObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +CompleteTaskPayload::CompleteTaskPayload() + : service::Object({ + "CompleteTaskPayload" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } }, + { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } } + }) +{ +} + +service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); +} + +std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getTask(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); +} + +std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getClientMutationId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema) +{ + typeCompleteTaskPayload->AddFields({ + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/CompleteTaskPayloadObject.h b/samples/separate_nointrospection/CompleteTaskPayloadObject.h new file mode 100644 index 00000000..8d7a122b --- /dev/null +++ b/samples/separate_nointrospection/CompleteTaskPayloadObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef COMPLETETASKPAYLOADOBJECT_H +#define COMPLETETASKPAYLOADOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class CompleteTaskPayload + : public service::Object +{ +protected: + explicit CompleteTaskPayload(); + +public: + virtual service::FieldResult> getTask(service::FieldParams&& params) const; + virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; + +private: + std::future resolveTask(service::ResolverParams&& params); + std::future resolveClientMutationId(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // COMPLETETASKPAYLOADOBJECT_H diff --git a/samples/separate_nointrospection/ExpensiveObject.cpp b/samples/separate_nointrospection/ExpensiveObject.cpp new file mode 100644 index 00000000..728081f4 --- /dev/null +++ b/samples/separate_nointrospection/ExpensiveObject.cpp @@ -0,0 +1,57 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Expensive::Expensive() + : service::Object({ + "Expensive" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } } + }) +{ +} + +service::FieldResult Expensive::getOrder(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); +} + +std::future Expensive::resolveOrder(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getOrder(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Expensive::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema) +{ + typeExpensive->AddFields({ + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/ExpensiveObject.h b/samples/separate_nointrospection/ExpensiveObject.h new file mode 100644 index 00000000..a435994a --- /dev/null +++ b/samples/separate_nointrospection/ExpensiveObject.h @@ -0,0 +1,30 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef EXPENSIVEOBJECT_H +#define EXPENSIVEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Expensive + : public service::Object +{ +protected: + explicit Expensive(); + +public: + virtual service::FieldResult getOrder(service::FieldParams&& params) const; + +private: + std::future resolveOrder(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // EXPENSIVEOBJECT_H diff --git a/samples/separate_nointrospection/FolderConnectionObject.cpp b/samples/separate_nointrospection/FolderConnectionObject.cpp new file mode 100644 index 00000000..d08718c8 --- /dev/null +++ b/samples/separate_nointrospection/FolderConnectionObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderConnection::FolderConnection() + : service::Object({ + "FolderConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); +} + +std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); +} + +std::future FolderConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future FolderConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema) +{ + typeFolderConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/FolderConnectionObject.h b/samples/separate_nointrospection/FolderConnectionObject.h new file mode 100644 index 00000000..9bcd2d4a --- /dev/null +++ b/samples/separate_nointrospection/FolderConnectionObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef FOLDERCONNECTIONOBJECT_H +#define FOLDERCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class FolderConnection + : public service::Object +{ +protected: + explicit FolderConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // FOLDERCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/FolderEdgeObject.cpp b/samples/separate_nointrospection/FolderEdgeObject.cpp new file mode 100644 index 00000000..0c8ba56b --- /dev/null +++ b/samples/separate_nointrospection/FolderEdgeObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +FolderEdge::FolderEdge() + : service::Object({ + "FolderEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); +} + +std::future FolderEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); +} + +std::future FolderEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future FolderEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema) +{ + typeFolderEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/FolderEdgeObject.h b/samples/separate_nointrospection/FolderEdgeObject.h new file mode 100644 index 00000000..4fc210d2 --- /dev/null +++ b/samples/separate_nointrospection/FolderEdgeObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef FOLDEREDGEOBJECT_H +#define FOLDEREDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class FolderEdge + : public service::Object +{ +protected: + explicit FolderEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // FOLDEREDGEOBJECT_H diff --git a/samples/separate_nointrospection/FolderObject.cpp b/samples/separate_nointrospection/FolderObject.cpp new file mode 100644 index 00000000..8cfbe7c0 --- /dev/null +++ b/samples/separate_nointrospection/FolderObject.cpp @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Folder::Folder() + : service::Object({ + "Node", + "UnionType", + "Folder" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } + }) +{ +} + +service::FieldResult Folder::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); +} + +std::future Folder::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Folder::getName(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); +} + +std::future Folder::resolveName(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); +} + +std::future Folder::resolveUnreadCount(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCount(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Folder::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema) +{ + typeFolder->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeFolder->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/FolderObject.h b/samples/separate_nointrospection/FolderObject.h new file mode 100644 index 00000000..13fd2c61 --- /dev/null +++ b/samples/separate_nointrospection/FolderObject.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef FOLDEROBJECT_H +#define FOLDEROBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Folder + : public service::Object + , public Node +{ +protected: + explicit Folder(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getName(service::FieldParams&& params) const; + virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveUnreadCount(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // FOLDEROBJECT_H diff --git a/samples/separate_nointrospection/MutationObject.cpp b/samples/separate_nointrospection/MutationObject.cpp new file mode 100644 index 00000000..ff147f37 --- /dev/null +++ b/samples/separate_nointrospection/MutationObject.cpp @@ -0,0 +1,79 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Mutation::Mutation() + : service::Object({ + "Mutation" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } }, + { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } } + }) +{ +} + +service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const +{ + throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); +} + +std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) +{ + auto argInput = service::ModifiedArgument::require("input", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = applyCompleteTask(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argInput)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const +{ + throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); +} + +std::future Mutation::resolveSetFloat(service::ResolverParams&& params) +{ + auto argValue = service::ModifiedArgument::require("value", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = applySetFloat(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argValue)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Mutation::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema) +{ + typeMutation->AddFields({ + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) + }) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/MutationObject.h b/samples/separate_nointrospection/MutationObject.h new file mode 100644 index 00000000..fcb6340f --- /dev/null +++ b/samples/separate_nointrospection/MutationObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef MUTATIONOBJECT_H +#define MUTATIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Mutation + : public service::Object +{ +protected: + explicit Mutation(); + +public: + virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; + virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; + +private: + std::future resolveCompleteTask(service::ResolverParams&& params); + std::future resolveSetFloat(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // MUTATIONOBJECT_H diff --git a/samples/separate_nointrospection/NestedTypeObject.cpp b/samples/separate_nointrospection/NestedTypeObject.cpp new file mode 100644 index 00000000..de6cda36 --- /dev/null +++ b/samples/separate_nointrospection/NestedTypeObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +NestedType::NestedType() + : service::Object({ + "NestedType" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } } + }) +{ +} + +service::FieldResult NestedType::getDepth(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); +} + +std::future NestedType::resolveDepth(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getDepth(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> NestedType::getNested(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); +} + +std::future NestedType::resolveNested(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future NestedType::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema) +{ + typeNestedType->AddFields({ + schema::Field::Make(R"gql(depth)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/NestedTypeObject.h b/samples/separate_nointrospection/NestedTypeObject.h new file mode 100644 index 00000000..8fa86966 --- /dev/null +++ b/samples/separate_nointrospection/NestedTypeObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef NESTEDTYPEOBJECT_H +#define NESTEDTYPEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class NestedType + : public service::Object +{ +protected: + explicit NestedType(); + +public: + virtual service::FieldResult getDepth(service::FieldParams&& params) const; + virtual service::FieldResult> getNested(service::FieldParams&& params) const; + +private: + std::future resolveDepth(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // NESTEDTYPEOBJECT_H diff --git a/samples/separate_nointrospection/PageInfoObject.cpp b/samples/separate_nointrospection/PageInfoObject.cpp new file mode 100644 index 00000000..eea08374 --- /dev/null +++ b/samples/separate_nointrospection/PageInfoObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +PageInfo::PageInfo() + : service::Object({ + "PageInfo" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, + { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } + }) +{ +} + +service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); +} + +std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getHasNextPage(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); +} + +std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getHasPreviousPage(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future PageInfo::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema) +{ + typePageInfo->AddFields({ + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/PageInfoObject.h b/samples/separate_nointrospection/PageInfoObject.h new file mode 100644 index 00000000..ca0108ab --- /dev/null +++ b/samples/separate_nointrospection/PageInfoObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef PAGEINFOOBJECT_H +#define PAGEINFOOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class PageInfo + : public service::Object +{ +protected: + explicit PageInfo(); + +public: + virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; + virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; + +private: + std::future resolveHasNextPage(service::ResolverParams&& params); + std::future resolveHasPreviousPage(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // PAGEINFOOBJECT_H diff --git a/samples/separate_nointrospection/QueryObject.cpp b/samples/separate_nointrospection/QueryObject.cpp new file mode 100644 index 00000000..2a6ffe7b --- /dev/null +++ b/samples/separate_nointrospection/QueryObject.cpp @@ -0,0 +1,262 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Query::Query() + : service::Object({ + "Query" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(appointments)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointments(std::move(params)); } }, + { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, + { R"gql(expensive)gql"sv, [this](service::ResolverParams&& params) { return resolveExpensive(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, + { R"gql(tasksById)gql"sv, [this](service::ResolverParams&& params) { return resolveTasksById(std::move(params)); } }, + { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, + { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, + { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } + }) +{ +} + +service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const +{ + throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); +} + +std::future Query::resolveNode(service::ResolverParams&& params) +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); +} + +std::future Query::resolveAppointments(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getAppointments(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); +} + +std::future Query::resolveTasks(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getTasks(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); +} + +std::future Query::resolveUnreadCounts(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCounts(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); +} + +std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +{ + const auto defaultArguments = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = []() + { + response::Value elements(response::Type::List); + response::Value entry; + + entry = response::Value(std::string(R"gql(ZmFrZUFwcG9pbnRtZW50SWQ=)gql")); + elements.emplace_back(std::move(entry)); + return elements; + }(); + values.emplace_back("ids", std::move(entry)); + + return values; + }(); + + auto pairIds = service::ModifiedArgument::find("ids", params.arguments); + auto argIds = (pairIds.second + ? std::move(pairIds.first) + : service::ModifiedArgument::require("ids", defaultArguments)); + std::unique_lock resolverLock(_resolverMutex); + auto result = getAppointmentsById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); +} + +std::future Query::resolveTasksById(service::ResolverParams&& params) +{ + auto argIds = service::ModifiedArgument::require("ids", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getTasksById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); +} + +std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +{ + auto argIds = service::ModifiedArgument::require("ids", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCountsById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getNested(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); +} + +std::future Query::resolveNested(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Query::getUnimplemented(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); +} + +std::future Query::resolveUnimplemented(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnimplemented(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getExpensive(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); +} + +std::future Query::resolveExpensive(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getExpensive(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Query::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema) +{ + typeQuery->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Node"), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointments)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(tasks)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + }), + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/QueryObject.h b/samples/separate_nointrospection/QueryObject.h new file mode 100644 index 00000000..20c73917 --- /dev/null +++ b/samples/separate_nointrospection/QueryObject.h @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef QUERYOBJECT_H +#define QUERYOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Query + : public service::Object +{ +protected: + explicit Query(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; + virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult> getNested(service::FieldParams&& params) const; + virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; + virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveAppointments(service::ResolverParams&& params); + std::future resolveTasks(service::ResolverParams&& params); + std::future resolveUnreadCounts(service::ResolverParams&& params); + std::future resolveAppointmentsById(service::ResolverParams&& params); + std::future resolveTasksById(service::ResolverParams&& params); + std::future resolveUnreadCountsById(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + std::future resolveUnimplemented(service::ResolverParams&& params); + std::future resolveExpensive(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // QUERYOBJECT_H diff --git a/samples/separate_nointrospection/SubscriptionObject.cpp b/samples/separate_nointrospection/SubscriptionObject.cpp new file mode 100644 index 00000000..1bb97a36 --- /dev/null +++ b/samples/separate_nointrospection/SubscriptionObject.cpp @@ -0,0 +1,76 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Subscription::Subscription() + : service::Object({ + "Subscription" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } }, + { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } } + }) +{ +} + +service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); +} + +std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNextAppointmentChange(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const +{ + throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); +} + +std::future Subscription::resolveNodeChange(service::ResolverParams&& params) +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getNodeChange(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Subscription::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema) +{ + typeSubscription->AddFields({ + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/SubscriptionObject.h b/samples/separate_nointrospection/SubscriptionObject.h new file mode 100644 index 00000000..6696710a --- /dev/null +++ b/samples/separate_nointrospection/SubscriptionObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef SUBSCRIPTIONOBJECT_H +#define SUBSCRIPTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Subscription + : public service::Object +{ +protected: + explicit Subscription(); + +public: + virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; + virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; + +private: + std::future resolveNextAppointmentChange(service::ResolverParams&& params); + std::future resolveNodeChange(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // SUBSCRIPTIONOBJECT_H diff --git a/samples/separate_nointrospection/TaskConnectionObject.cpp b/samples/separate_nointrospection/TaskConnectionObject.cpp new file mode 100644 index 00000000..cb744845 --- /dev/null +++ b/samples/separate_nointrospection/TaskConnectionObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskConnection::TaskConnection() + : service::Object({ + "TaskConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); +} + +std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); +} + +std::future TaskConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future TaskConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema) +{ + typeTaskConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/TaskConnectionObject.h b/samples/separate_nointrospection/TaskConnectionObject.h new file mode 100644 index 00000000..3b27f775 --- /dev/null +++ b/samples/separate_nointrospection/TaskConnectionObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TASKCONNECTIONOBJECT_H +#define TASKCONNECTIONOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class TaskConnection + : public service::Object +{ +protected: + explicit TaskConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // TASKCONNECTIONOBJECT_H diff --git a/samples/separate_nointrospection/TaskEdgeObject.cpp b/samples/separate_nointrospection/TaskEdgeObject.cpp new file mode 100644 index 00000000..adbe7362 --- /dev/null +++ b/samples/separate_nointrospection/TaskEdgeObject.cpp @@ -0,0 +1,73 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +TaskEdge::TaskEdge() + : service::Object({ + "TaskEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); +} + +std::future TaskEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); +} + +std::future TaskEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future TaskEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema) +{ + typeTaskEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/TaskEdgeObject.h b/samples/separate_nointrospection/TaskEdgeObject.h new file mode 100644 index 00000000..27b60417 --- /dev/null +++ b/samples/separate_nointrospection/TaskEdgeObject.h @@ -0,0 +1,32 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TASKEDGEOBJECT_H +#define TASKEDGEOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class TaskEdge + : public service::Object +{ +protected: + explicit TaskEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // TASKEDGEOBJECT_H diff --git a/samples/separate_nointrospection/TaskObject.cpp b/samples/separate_nointrospection/TaskObject.cpp new file mode 100644 index 00000000..f766136f --- /dev/null +++ b/samples/separate_nointrospection/TaskObject.cpp @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql::today { +namespace object { + +Task::Task() + : service::Object({ + "Node", + "UnionType", + "Task" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } }, + { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } } + }) +{ +} + +service::FieldResult Task::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); +} + +std::future Task::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Task::getTitle(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); +} + +std::future Task::resolveTitle(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getTitle(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Task::getIsComplete(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); +} + +std::future Task::resolveIsComplete(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getIsComplete(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Task::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); +} + +} /* namespace object */ + +void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema) +{ + typeTask->AddInterfaces({ + std::static_pointer_cast(schema->LookupType(R"gql(Node)gql"sv)) + }); + typeTask->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + }); +} + +} /* namespace graphql::today */ diff --git a/samples/separate_nointrospection/TaskObject.h b/samples/separate_nointrospection/TaskObject.h new file mode 100644 index 00000000..a6652cca --- /dev/null +++ b/samples/separate_nointrospection/TaskObject.h @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TASKOBJECT_H +#define TASKOBJECT_H + +#include "TodaySchema.h" + +namespace graphql::today::object { + +class Task + : public service::Object + , public Node +{ +protected: + explicit Task(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getTitle(service::FieldParams&& params) const; + virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveTitle(service::ResolverParams&& params); + std::future resolveIsComplete(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace graphql::today::object */ + +#endif // TASKOBJECT_H diff --git a/samples/separate_nointrospection/TodayObjects.h b/samples/separate_nointrospection/TodayObjects.h new file mode 100644 index 00000000..37b473ec --- /dev/null +++ b/samples/separate_nointrospection/TodayObjects.h @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TODAYOBJECTS_H +#define TODAYOBJECTS_H + +#include "TodaySchema.h" + +#include "QueryObject.h" +#include "PageInfoObject.h" +#include "AppointmentEdgeObject.h" +#include "AppointmentConnectionObject.h" +#include "TaskEdgeObject.h" +#include "TaskConnectionObject.h" +#include "FolderEdgeObject.h" +#include "FolderConnectionObject.h" +#include "CompleteTaskPayloadObject.h" +#include "MutationObject.h" +#include "SubscriptionObject.h" +#include "AppointmentObject.h" +#include "TaskObject.h" +#include "FolderObject.h" +#include "NestedTypeObject.h" +#include "ExpensiveObject.h" + +#endif // TODAYOBJECTS_H diff --git a/samples/separate_nointrospection/TodaySchema.cpp b/samples/separate_nointrospection/TodaySchema.cpp new file mode 100644 index 00000000..1a013746 --- /dev/null +++ b/samples/separate_nointrospection/TodaySchema.cpp @@ -0,0 +1,246 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayObjects.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql { +namespace service { + +static const std::array s_namesTaskState = { + "New", + "Started", + "Complete", + "Unassigned" +}; + +template <> +today::TaskState ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { "not a valid TaskState value" } }; + } + + auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + + if (itr == s_namesTaskState.cend()) + { + throw service::schema_exception { { "not a valid TaskState value" } }; + } + + return static_cast(itr - s_namesTaskState.cbegin()); +} + +template <> +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +{ + return resolve(std::move(result), std::move(params), + [](today::TaskState&& value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string(s_namesTaskState[static_cast(value)])); + + return result; + }); +} + +template <> +today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) +{ + const auto defaultValue = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = response::Value(true); + values.emplace_back("isComplete", std::move(entry)); + + return values; + }(); + + auto valueId = service::ModifiedArgument::require("id", value); + auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); + auto valueIsComplete = (pairIsComplete.second + ? std::move(pairIsComplete.first) + : service::ModifiedArgument::require("isComplete", defaultValue)); + auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); + + return { + std::move(valueId), + std::move(valueIsComplete), + std::move(valueClientMutationId) + }; +} + +} /* namespace service */ + +namespace today { + +Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : service::Request({ + { "query", query }, + { "mutation", mutation }, + { "subscription", subscription } + }, GetSchema()) + , _query(std::move(query)) + , _mutation(std::move(mutation)) + , _subscription(std::move(subscription)) +{ +} + +void AddTypesToSchema(const std::shared_ptr& schema) +{ + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); + schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); + auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Node)gql"sv, typeNode); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + schema->AddType(R"gql(Task)gql"sv, typeTask); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + schema->AddType(R"gql(Folder)gql"sv, typeFolder); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md()md"); + schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); + + typeTaskState->AddEnumValues({ + { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv) } + }); + + typeCompleteTaskInput->AddInputValues({ + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + }); + + typeUnionType->AddPossibleTypes({ + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) + }); + + typeNode->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + }); + + AddQueryDetails(typeQuery, schema); + AddPageInfoDetails(typePageInfo, schema); + AddAppointmentEdgeDetails(typeAppointmentEdge, schema); + AddAppointmentConnectionDetails(typeAppointmentConnection, schema); + AddTaskEdgeDetails(typeTaskEdge, schema); + AddTaskConnectionDetails(typeTaskConnection, schema); + AddFolderEdgeDetails(typeFolderEdge, schema); + AddFolderConnectionDetails(typeFolderConnection, schema); + AddCompleteTaskPayloadDetails(typeCompleteTaskPayload, schema); + AddMutationDetails(typeMutation, schema); + AddSubscriptionDetails(typeSubscription, schema); + AddAppointmentDetails(typeAppointment, schema); + AddTaskDetails(typeTask, schema); + AddFolderDetails(typeFolder, schema); + AddNestedTypeDetails(typeNestedType, schema); + AddExpensiveDetails(typeExpensive, schema); + + schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION + })); + schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::SUBSCRIPTION + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::QUERY + }, { + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_DEFINITION + }, { + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_SPREAD + }, { + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + + schema->AddQueryType(typeQuery); + schema->AddMutationType(typeMutation); + schema->AddSubscriptionType(typeSubscription); +} + +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(true); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + +} /* namespace today */ +} /* namespace graphql */ diff --git a/samples/separate_nointrospection/TodaySchema.h b/samples/separate_nointrospection/TodaySchema.h new file mode 100644 index 00000000..11a78db8 --- /dev/null +++ b/samples/separate_nointrospection/TodaySchema.h @@ -0,0 +1,94 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TODAYSCHEMA_H +#define TODAYSCHEMA_H + +#include "graphqlservice/GraphQLSchema.h" +#include "graphqlservice/GraphQLService.h" + +#include +#include +#include + +namespace graphql { +namespace today { + +enum class TaskState +{ + New, + Started, + Complete, + Unassigned +}; + +struct CompleteTaskInput +{ + response::IdType id; + std::optional isComplete; + std::optional clientMutationId; +}; + +namespace object { + +class Query; +class PageInfo; +class AppointmentEdge; +class AppointmentConnection; +class TaskEdge; +class TaskConnection; +class FolderEdge; +class FolderConnection; +class CompleteTaskPayload; +class Mutation; +class Subscription; +class Appointment; +class Task; +class Folder; +class NestedType; +class Expensive; + +} /* namespace object */ + +struct Node +{ + virtual service::FieldResult getId(service::FieldParams&& params) const = 0; +}; + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; +}; + +void AddQueryDetails(std::shared_ptr typeQuery, const std::shared_ptr& schema); +void AddPageInfoDetails(std::shared_ptr typePageInfo, const std::shared_ptr& schema); +void AddAppointmentEdgeDetails(std::shared_ptr typeAppointmentEdge, const std::shared_ptr& schema); +void AddAppointmentConnectionDetails(std::shared_ptr typeAppointmentConnection, const std::shared_ptr& schema); +void AddTaskEdgeDetails(std::shared_ptr typeTaskEdge, const std::shared_ptr& schema); +void AddTaskConnectionDetails(std::shared_ptr typeTaskConnection, const std::shared_ptr& schema); +void AddFolderEdgeDetails(std::shared_ptr typeFolderEdge, const std::shared_ptr& schema); +void AddFolderConnectionDetails(std::shared_ptr typeFolderConnection, const std::shared_ptr& schema); +void AddCompleteTaskPayloadDetails(std::shared_ptr typeCompleteTaskPayload, const std::shared_ptr& schema); +void AddMutationDetails(std::shared_ptr typeMutation, const std::shared_ptr& schema); +void AddSubscriptionDetails(std::shared_ptr typeSubscription, const std::shared_ptr& schema); +void AddAppointmentDetails(std::shared_ptr typeAppointment, const std::shared_ptr& schema); +void AddTaskDetails(std::shared_ptr typeTask, const std::shared_ptr& schema); +void AddFolderDetails(std::shared_ptr typeFolder, const std::shared_ptr& schema); +void AddNestedTypeDetails(std::shared_ptr typeNestedType, const std::shared_ptr& schema); +void AddExpensiveDetails(std::shared_ptr typeExpensive, const std::shared_ptr& schema); + +std::shared_ptr GetSchema(); + +} /* namespace today */ +} /* namespace graphql */ + +#endif // TODAYSCHEMA_H diff --git a/samples/separate_nointrospection/today_schema_files b/samples/separate_nointrospection/today_schema_files new file mode 100644 index 00000000..f1fb1229 --- /dev/null +++ b/samples/separate_nointrospection/today_schema_files @@ -0,0 +1,17 @@ +TodaySchema.cpp +QueryObject.cpp +PageInfoObject.cpp +AppointmentEdgeObject.cpp +AppointmentConnectionObject.cpp +TaskEdgeObject.cpp +TaskConnectionObject.cpp +FolderEdgeObject.cpp +FolderConnectionObject.cpp +CompleteTaskPayloadObject.cpp +MutationObject.cpp +SubscriptionObject.cpp +AppointmentObject.cpp +TaskObject.cpp +FolderObject.cpp +NestedTypeObject.cpp +ExpensiveObject.cpp diff --git a/samples/today/TodayMock.h b/samples/today/TodayMock.h index cb43c6f9..02ba2b0c 100644 --- a/samples/today/TodayMock.h +++ b/samples/today/TodayMock.h @@ -154,6 +154,12 @@ class Appointment : public object::Appointment return _isNow; } + service::FieldResult> getForceError( + service::FieldParams&&) const final + { + throw std::runtime_error(R"ex(this error was forced)ex"); + } + private: response::IdType _id; std::string _when; diff --git a/samples/today/benchmark.cpp b/samples/today/benchmark.cpp new file mode 100644 index 00000000..765a2ef1 --- /dev/null +++ b/samples/today/benchmark.cpp @@ -0,0 +1,115 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodayMock.h" + +#include "graphqlservice/JSONResponse.h" + +#include +#include +#include +#include +#include + +using namespace graphql; + +int main(int argc, char** argv) +{ + response::IdType binAppointmentId; + response::IdType binTaskId; + response::IdType binFolderId; + + std::string fakeAppointmentId("fakeAppointmentId"); + binAppointmentId.resize(fakeAppointmentId.size()); + std::copy(fakeAppointmentId.cbegin(), fakeAppointmentId.cend(), binAppointmentId.begin()); + + std::string fakeTaskId("fakeTaskId"); + binTaskId.resize(fakeTaskId.size()); + std::copy(fakeTaskId.cbegin(), fakeTaskId.cend(), binTaskId.begin()); + + std::string fakeFolderId("fakeFolderId"); + binFolderId.resize(fakeFolderId.size()); + std::copy(fakeFolderId.cbegin(), fakeFolderId.cend(), binFolderId.begin()); + + auto query = std::make_shared( + [&binAppointmentId]() -> std::vector> { + std::cout << "Called getAppointments..." << std::endl; + return { std::make_shared(std::move(binAppointmentId), + "tomorrow", + "Lunch?", + false) }; + }, + [&binTaskId]() -> std::vector> { + std::cout << "Called getTasks..." << std::endl; + return { std::make_shared(std::move(binTaskId), "Don't forget", true) }; + }, + [&binFolderId]() -> std::vector> { + std::cout << "Called getUnreadCounts..." << std::endl; + return { std::make_shared(std::move(binFolderId), "\"Fake\" Inbox", 3) }; + }); + auto mutation = std::make_shared( + [](today::CompleteTaskInput&& input) -> std::shared_ptr { + return std::make_shared( + std::make_shared(std::move(input.id), + "Mutated Task!", + *(input.isComplete)), + std::move(input.clientMutationId)); + }); + auto subscription = std::make_shared(); + auto service = std::make_shared(query, mutation, subscription); + + std::cout << "Created the service..." << std::endl; + + const size_t iterations = [](const char* arg) noexcept -> size_t { + if (arg) + { + const int parsed = std::atoi(arg); + + if (parsed > 0) + { + return static_cast(parsed); + } + } + + // Default to 100 iterations + return 100; + }((argc > 1) ? argv[1] : nullptr); + + for (size_t i = 0; i < iterations; ++i) + { + try + { + auto query = R"gql(query { + appointments { + pageInfo { hasNextPage } + edges { + node { + id + when + subject + isNow + } + } + } + })gql"_graphql; + +#ifdef NO_INTROSPECTION + // TODO: cherry-pick validation support without Introspection + query.validated = true; +#endif // NO_INTROSPECTION + + std::cout << "Executing query..." << std::endl; + + std::cout << response::toJSON( + service->resolve(nullptr, query, "", response::Value(response::Type::Map)).get()) + << std::endl; + } + catch (const std::runtime_error& ex) + { + std::cerr << ex.what() << std::endl; + return 1; + } + } + + return 0; +} diff --git a/samples/today/sample.cpp b/samples/today/sample.cpp index 376a7300..494c0b5c 100644 --- a/samples/today/sample.cpp +++ b/samples/today/sample.cpp @@ -82,6 +82,11 @@ int main(int argc, char** argv) return 1; } +#ifdef NO_INTROSPECTION + // TODO: cherry-pick validation support without Introspection + query.validated = true; +#endif // NO_INTROSPECTION + std::cout << "Executing query..." << std::endl; std::cout << response::toJSON(service diff --git a/samples/unified/TodaySchema.cpp b/samples/unified/TodaySchema.cpp index 325b73ae..754e9b49 100644 --- a/samples/unified/TodaySchema.cpp +++ b/samples/unified/TodaySchema.cpp @@ -3,7 +3,7 @@ #include "TodaySchema.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -45,7 +45,7 @@ today::TaskState ModifiedArgument::convert(const response::Val } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](today::TaskState&& value, const ResolverParams&) @@ -109,10 +109,8 @@ Query::Query() { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } }) - , _schema(std::make_shared()) + , _schema(GetSchema()) { - introspection::AddTypesToSchema(_schema); - today::AddTypesToSchema(_schema); } service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const @@ -120,7 +118,7 @@ service::FieldResult> Query::getNode(service::F throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); } -std::future Query::resolveNode(service::ResolverParams&& params) +std::future Query::resolveNode(service::ResolverParams&& params) { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -135,7 +133,7 @@ service::FieldResult> Query::getAppointme throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); } -std::future Query::resolveAppointments(service::ResolverParams&& params) +std::future Query::resolveAppointments(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -153,7 +151,7 @@ service::FieldResult> Query::getTasks(service::F throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); } -std::future Query::resolveTasks(service::ResolverParams&& params) +std::future Query::resolveTasks(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -171,7 +169,7 @@ service::FieldResult> Query::getUnreadCounts(s throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); } -std::future Query::resolveUnreadCounts(service::ResolverParams&& params) +std::future Query::resolveUnreadCounts(service::ResolverParams&& params) { auto argFirst = service::ModifiedArgument::require("first", params.arguments); auto argAfter = service::ModifiedArgument::require("after", params.arguments); @@ -189,7 +187,7 @@ service::FieldResult>> Query::getAppoin throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); } -std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +std::future Query::resolveAppointmentsById(service::ResolverParams&& params) { const auto defaultArguments = []() { @@ -226,7 +224,7 @@ service::FieldResult>> Query::getTasksById(ser throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); } -std::future Query::resolveTasksById(service::ResolverParams&& params) +std::future Query::resolveTasksById(service::ResolverParams&& params) { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -241,7 +239,7 @@ service::FieldResult>> Query::getUnreadCount throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); } -std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) { auto argIds = service::ModifiedArgument::require("ids", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -256,7 +254,7 @@ service::FieldResult> Query::getNested(service::Fiel throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); } -std::future Query::resolveNested(service::ResolverParams&& params) +std::future Query::resolveNested(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -270,7 +268,7 @@ service::FieldResult Query::getUnimplemented(service::Fiel throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); } -std::future Query::resolveUnimplemented(service::ResolverParams&& params) +std::future Query::resolveUnimplemented(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getUnimplemented(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -284,7 +282,7 @@ service::FieldResult>> Query::getExpensiv throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); } -std::future Query::resolveExpensive(service::ResolverParams&& params) +std::future Query::resolveExpensive(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getExpensive(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -293,21 +291,23 @@ std::future Query::resolveExpensive(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolve_typename(service::ResolverParams&& params) +std::future Query::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); } -std::future Query::resolve_schema(service::ResolverParams&& params) +std::future Query::resolve_schema(service::ResolverParams&& params) { - return service::ModifiedResult::convert(std::static_pointer_cast(_schema), std::move(params)); + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); } -std::future Query::resolve_type(service::ResolverParams&& params) +std::future Query::resolve_type(service::ResolverParams&& params) { auto argName = service::ModifiedArgument::require("name", params.arguments); + const auto& baseType = _schema->LookupType(argName); + std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - return service::ModifiedResult::convert(_schema->LookupType(argName), std::move(params)); + return service::ModifiedResult::convert(result, std::move(params)); } PageInfo::PageInfo() @@ -326,7 +326,7 @@ service::FieldResult PageInfo::getHasNextPage(service::Fi throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); } -std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) +std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHasNextPage(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -340,7 +340,7 @@ service::FieldResult PageInfo::getHasPreviousPage(service throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); } -std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) +std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHasPreviousPage(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -349,7 +349,7 @@ std::future PageInfo::resolveHasPreviousPage(service::ResolverP return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future PageInfo::resolve_typename(service::ResolverParams&& params) +std::future PageInfo::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); } @@ -370,7 +370,7 @@ service::FieldResult> AppointmentEdge::getNode(serv throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); } -std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) +std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -384,7 +384,7 @@ service::FieldResult AppointmentEdge::getCursor(service::FieldP throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); } -std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) +std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -393,7 +393,7 @@ std::future AppointmentEdge::resolveCursor(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) +std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); } @@ -414,7 +414,7 @@ service::FieldResult> AppointmentConnection::getPageIn throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); } -std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) +std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -428,7 +428,7 @@ service::FieldResult> throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); } -std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) +std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -437,7 +437,7 @@ std::future AppointmentConnection::resolveEdges(service::Resolv return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) +std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); } @@ -458,7 +458,7 @@ service::FieldResult> TaskEdge::getNode(service::FieldPara throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); } -std::future TaskEdge::resolveNode(service::ResolverParams&& params) +std::future TaskEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -472,7 +472,7 @@ service::FieldResult TaskEdge::getCursor(service::FieldParams&& throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); } -std::future TaskEdge::resolveCursor(service::ResolverParams&& params) +std::future TaskEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -481,7 +481,7 @@ std::future TaskEdge::resolveCursor(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future TaskEdge::resolve_typename(service::ResolverParams&& params) +std::future TaskEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); } @@ -502,7 +502,7 @@ service::FieldResult> TaskConnection::getPageInfo(serv throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); } -std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) +std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -516,7 +516,7 @@ service::FieldResult>>> Task throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); } -std::future TaskConnection::resolveEdges(service::ResolverParams&& params) +std::future TaskConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -525,7 +525,7 @@ std::future TaskConnection::resolveEdges(service::ResolverParam return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future TaskConnection::resolve_typename(service::ResolverParams&& params) +std::future TaskConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); } @@ -546,7 +546,7 @@ service::FieldResult> FolderEdge::getNode(service::Field throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); } -std::future FolderEdge::resolveNode(service::ResolverParams&& params) +std::future FolderEdge::resolveNode(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -560,7 +560,7 @@ service::FieldResult FolderEdge::getCursor(service::FieldParams throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); } -std::future FolderEdge::resolveCursor(service::ResolverParams&& params) +std::future FolderEdge::resolveCursor(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -569,7 +569,7 @@ std::future FolderEdge::resolveCursor(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future FolderEdge::resolve_typename(service::ResolverParams&& params) +std::future FolderEdge::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); } @@ -590,7 +590,7 @@ service::FieldResult> FolderConnection::getPageInfo(se throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); } -std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) +std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -604,7 +604,7 @@ service::FieldResult>>> Fo throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); } -std::future FolderConnection::resolveEdges(service::ResolverParams&& params) +std::future FolderConnection::resolveEdges(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -613,7 +613,7 @@ std::future FolderConnection::resolveEdges(service::ResolverPar return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future FolderConnection::resolve_typename(service::ResolverParams&& params) +std::future FolderConnection::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); } @@ -634,7 +634,7 @@ service::FieldResult> CompleteTaskPayload::getTask(service throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); } -std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getTask(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -648,7 +648,7 @@ service::FieldResult> CompleteTaskPayload::g throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); } -std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getClientMutationId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -657,7 +657,7 @@ std::future CompleteTaskPayload::resolveClientMutationId(servic return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) +std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); } @@ -678,7 +678,7 @@ service::FieldResult> Mutation::applyComple throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); } -std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) +std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) { auto argInput = service::ModifiedArgument::require("input", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -693,7 +693,7 @@ service::FieldResult Mutation::applySetFloat(service::Field throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); } -std::future Mutation::resolveSetFloat(service::ResolverParams&& params) +std::future Mutation::resolveSetFloat(service::ResolverParams&& params) { auto argValue = service::ModifiedArgument::require("value", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -703,7 +703,7 @@ std::future Mutation::resolveSetFloat(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Mutation::resolve_typename(service::ResolverParams&& params) +std::future Mutation::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); } @@ -724,7 +724,7 @@ service::FieldResult> Subscription::getNextAppointm throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); } -std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) +std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNextAppointmentChange(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -738,7 +738,7 @@ service::FieldResult> Subscription::getNodeChan throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); } -std::future Subscription::resolveNodeChange(service::ResolverParams&& params) +std::future Subscription::resolveNodeChange(service::ResolverParams&& params) { auto argId = service::ModifiedArgument::require("id", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -748,7 +748,7 @@ std::future Subscription::resolveNodeChange(service::ResolverPa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Subscription::resolve_typename(service::ResolverParams&& params) +std::future Subscription::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); } @@ -760,6 +760,7 @@ Appointment::Appointment() "Appointment" }, { { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } }, { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, @@ -773,7 +774,7 @@ service::FieldResult Appointment::getId(service::FieldParams&& throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); } -std::future Appointment::resolveId(service::ResolverParams&& params) +std::future Appointment::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -787,7 +788,7 @@ service::FieldResult> Appointment::getWhen(servic throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); } -std::future Appointment::resolveWhen(service::ResolverParams&& params) +std::future Appointment::resolveWhen(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getWhen(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -801,7 +802,7 @@ service::FieldResult> Appointment::getSubjec throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); } -std::future Appointment::resolveSubject(service::ResolverParams&& params) +std::future Appointment::resolveSubject(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getSubject(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -815,7 +816,7 @@ service::FieldResult Appointment::getIsNow(service::Field throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); } -std::future Appointment::resolveIsNow(service::ResolverParams&& params) +std::future Appointment::resolveIsNow(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsNow(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -824,7 +825,21 @@ std::future Appointment::resolveIsNow(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Appointment::resolve_typename(service::ResolverParams&& params) +service::FieldResult> Appointment::getForceError(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); +} + +std::future Appointment::resolveForceError(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getForceError(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Appointment::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); } @@ -848,7 +863,7 @@ service::FieldResult Task::getId(service::FieldParams&&) const throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); } -std::future Task::resolveId(service::ResolverParams&& params) +std::future Task::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -862,7 +877,7 @@ service::FieldResult> Task::getTitle(service throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); } -std::future Task::resolveTitle(service::ResolverParams&& params) +std::future Task::resolveTitle(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getTitle(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -876,7 +891,7 @@ service::FieldResult Task::getIsComplete(service::FieldPa throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); } -std::future Task::resolveIsComplete(service::ResolverParams&& params) +std::future Task::resolveIsComplete(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getIsComplete(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -885,7 +900,7 @@ std::future Task::resolveIsComplete(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Task::resolve_typename(service::ResolverParams&& params) +std::future Task::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); } @@ -909,7 +924,7 @@ service::FieldResult Folder::getId(service::FieldParams&&) con throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); } -std::future Folder::resolveId(service::ResolverParams&& params) +std::future Folder::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -923,7 +938,7 @@ service::FieldResult> Folder::getName(servic throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); } -std::future Folder::resolveName(service::ResolverParams&& params) +std::future Folder::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -937,7 +952,7 @@ service::FieldResult Folder::getUnreadCount(service::FieldPar throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); } -std::future Folder::resolveUnreadCount(service::ResolverParams&& params) +std::future Folder::resolveUnreadCount(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getUnreadCount(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -946,7 +961,7 @@ std::future Folder::resolveUnreadCount(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Folder::resolve_typename(service::ResolverParams&& params) +std::future Folder::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); } @@ -967,7 +982,7 @@ service::FieldResult NestedType::getDepth(service::FieldParam throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); } -std::future NestedType::resolveDepth(service::ResolverParams&& params) +std::future NestedType::resolveDepth(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDepth(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -981,7 +996,7 @@ service::FieldResult> NestedType::getNested(service: throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); } -std::future NestedType::resolveNested(service::ResolverParams&& params) +std::future NestedType::resolveNested(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -990,7 +1005,7 @@ std::future NestedType::resolveNested(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future NestedType::resolve_typename(service::ResolverParams&& params) +std::future NestedType::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); } @@ -1010,7 +1025,7 @@ service::FieldResult Expensive::getOrder(service::FieldParams throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); } -std::future Expensive::resolveOrder(service::ResolverParams&& params) +std::future Expensive::resolveOrder(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getOrder(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -1019,7 +1034,7 @@ std::future Expensive::resolveOrder(service::ResolverParams&& p return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Expensive::resolve_typename(service::ResolverParams&& params) +std::future Expensive::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); } @@ -1031,233 +1046,250 @@ Operations::Operations(std::shared_ptr query, std::shared_ptr& schema) -{ - schema->AddType("ItemCursor", std::make_shared("ItemCursor", R"md()md")); - schema->AddType("DateTime", std::make_shared("DateTime", R"md()md")); - auto typeTaskState = std::make_shared("TaskState", R"md()md"); - schema->AddType("TaskState", typeTaskState); - auto typeCompleteTaskInput = std::make_shared("CompleteTaskInput", R"md()md"); - schema->AddType("CompleteTaskInput", typeCompleteTaskInput); - auto typeUnionType = std::make_shared("UnionType", R"md()md"); - schema->AddType("UnionType", typeUnionType); - auto typeNode = std::make_shared("Node", R"md(Node interface for Relay support)md"); - schema->AddType("Node", typeNode); - auto typeQuery = std::make_shared("Query", R"md(Root Query type)md"); - schema->AddType("Query", typeQuery); - auto typePageInfo = std::make_shared("PageInfo", R"md()md"); - schema->AddType("PageInfo", typePageInfo); - auto typeAppointmentEdge = std::make_shared("AppointmentEdge", R"md()md"); - schema->AddType("AppointmentEdge", typeAppointmentEdge); - auto typeAppointmentConnection = std::make_shared("AppointmentConnection", R"md()md"); - schema->AddType("AppointmentConnection", typeAppointmentConnection); - auto typeTaskEdge = std::make_shared("TaskEdge", R"md()md"); - schema->AddType("TaskEdge", typeTaskEdge); - auto typeTaskConnection = std::make_shared("TaskConnection", R"md()md"); - schema->AddType("TaskConnection", typeTaskConnection); - auto typeFolderEdge = std::make_shared("FolderEdge", R"md()md"); - schema->AddType("FolderEdge", typeFolderEdge); - auto typeFolderConnection = std::make_shared("FolderConnection", R"md()md"); - schema->AddType("FolderConnection", typeFolderConnection); - auto typeCompleteTaskPayload = std::make_shared("CompleteTaskPayload", R"md()md"); - schema->AddType("CompleteTaskPayload", typeCompleteTaskPayload); - auto typeMutation = std::make_shared("Mutation", R"md()md"); - schema->AddType("Mutation", typeMutation); - auto typeSubscription = std::make_shared("Subscription", R"md()md"); - schema->AddType("Subscription", typeSubscription); - auto typeAppointment = std::make_shared("Appointment", R"md()md"); - schema->AddType("Appointment", typeAppointment); - auto typeTask = std::make_shared("Task", R"md()md"); - schema->AddType("Task", typeTask); - auto typeFolder = std::make_shared("Folder", R"md()md"); - schema->AddType("Folder", typeFolder); - auto typeNestedType = std::make_shared("NestedType", R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); - schema->AddType("NestedType", typeNestedType); - auto typeExpensive = std::make_shared("Expensive", R"md()md"); - schema->AddType("Expensive", typeExpensive); +void AddTypesToSchema(const std::shared_ptr& schema) +{ + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); + schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); + auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md(Node interface for Relay support)md"sv); + schema->AddType(R"gql(Node)gql"sv, typeNode); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(Root Query type)md"); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + schema->AddType(R"gql(Task)gql"sv, typeTask); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + schema->AddType(R"gql(Folder)gql"sv, typeFolder); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md(Infinitely nestable type which can be used with nested fragments to test directive handling)md"); + schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); typeTaskState->AddEnumValues({ - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::New)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Started)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Complete)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesTaskState[static_cast(today::TaskState::Unassigned)] }, R"md()md", std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md") } + { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv) } }); typeCompleteTaskInput->AddInputValues({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"), - std::make_shared("isComplete", R"md()md", schema->LookupType("Boolean"), R"gql(true)gql"), - std::make_shared("clientMutationId", R"md()md", schema->LookupType("String"), R"gql()gql") + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) }); typeUnionType->AddPossibleTypes({ - schema->LookupType("Appointment"), - schema->LookupType("Task"), - schema->LookupType("Folder") + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) }); typeNode->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) }); typeQuery->AddFields({ - std::make_shared("node", R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md", std::nullopt, std::vector>({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql") - }), schema->LookupType("Node")), - std::make_shared("appointments", R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection"))), - std::make_shared("tasks", R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection"))), - std::make_shared("unreadCounts", R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md", std::nullopt, std::vector>({ - std::make_shared("first", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("after", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql"), - std::make_shared("last", R"md()md", schema->LookupType("Int"), R"gql()gql"), - std::make_shared("before", R"md()md", schema->LookupType("ItemCursor"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection"))), - std::make_shared("appointmentsById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment")))), - std::make_shared("tasksById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task")))), - std::make_shared("unreadCountsById", R"md()md", std::nullopt, std::vector>({ - std::make_shared("ids", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder")))), - std::make_shared("nested", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), - std::make_shared("unimplemented", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("expensive", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) + schema::Field::Make(R"gql(node)gql"sv, R"md([Object Identification](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#object-identification))md"sv, std::nullopt, schema->LookupType("Node"), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointments)gql"sv, R"md(Appointments [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(tasks)gql"sv, R"md(Tasks [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md(Folder unread counts [Connection](https://facebook.github.io/relay/docs/en/graphql-server-specification.html#connections))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + }), + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) }); typePageInfo->AddFields({ - std::make_shared("hasNextPage", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("hasPreviousPage", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) }); typeAppointmentEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Appointment")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); typeAppointmentConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) }); typeTaskEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Task")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); typeTaskConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) }); typeFolderEdge->AddFields({ - std::make_shared("node", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Folder")), - std::make_shared("cursor", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) }); typeFolderConnection->AddFields({ - std::make_shared("pageInfo", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), - std::make_shared("edges", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) }); typeCompleteTaskPayload->AddFields({ - std::make_shared("task", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Task")), - std::make_shared("clientMutationId", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeMutation->AddFields({ - std::make_shared("completeTask", R"md()md", std::nullopt, std::vector>({ - std::make_shared("input", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload"))), - std::make_shared("setFloat", R"md()md", std::nullopt, std::vector>({ - std::make_shared("value", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float"))) + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) + }) }); typeSubscription->AddFields({ - std::make_shared("nextAppointmentChange", R"md()md", std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"), std::vector>(), schema->LookupType("Appointment")), - std::make_shared("nodeChange", R"md()md", std::nullopt, std::vector>({ - std::make_shared("id", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node"))) + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }) }); typeAppointment->AddInterfaces({ typeNode }); typeAppointment->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("when", R"md()md", std::nullopt, std::vector>(), schema->LookupType("DateTime")), - std::make_shared("subject", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("isNow", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeTask->AddInterfaces({ typeNode }); typeTask->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("title", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("isComplete", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) }); typeFolder->AddInterfaces({ typeNode }); typeFolder->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("unreadCount", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) }); typeNestedType->AddFields({ - std::make_shared("depth", R"md(Depth of the nested element)md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - std::make_shared("nested", R"md(Link to the next level)md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) + schema::Field::Make(R"gql(depth)gql"sv, R"md(Depth of the nested element)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), + schema::Field::Make(R"gql(nested)gql"sv, R"md(Link to the next level)md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) }); typeExpensive->AddFields({ - std::make_shared("order", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) }); - schema->AddDirective(std::make_shared("id", R"md()md", std::vector({ - R"gql(FIELD_DEFINITION)gql" - }), std::vector>())); - schema->AddDirective(std::make_shared("subscriptionTag", R"md()md", std::vector({ - R"gql(SUBSCRIPTION)gql" - }), std::vector>({ - std::make_shared("field", R"md()md", schema->LookupType("String"), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("queryTag", R"md()md", std::vector({ - R"gql(QUERY)gql" - }), std::vector>({ - std::make_shared("query", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fieldTag", R"md()md", std::vector({ - R"gql(FIELD)gql" - }), std::vector>({ - std::make_shared("field", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fragmentDefinitionTag", R"md()md", std::vector({ - R"gql(FRAGMENT_DEFINITION)gql" - }), std::vector>({ - std::make_shared("fragmentDefinition", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("fragmentSpreadTag", R"md()md", std::vector({ - R"gql(FRAGMENT_SPREAD)gql" - }), std::vector>({ - std::make_shared("fragmentSpread", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); - schema->AddDirective(std::make_shared("inlineFragmentTag", R"md()md", std::vector({ - R"gql(INLINE_FRAGMENT)gql" - }), std::vector>({ - std::make_shared("inlineFragment", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql") - }))); + schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION + })); + schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::SUBSCRIPTION + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::QUERY + }, { + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_DEFINITION + }, { + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_SPREAD + }, { + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); schema->AddQueryType(typeQuery); schema->AddMutationType(typeMutation); schema->AddSubscriptionType(typeSubscription); } +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(false); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + } /* namespace today */ } /* namespace graphql */ diff --git a/samples/unified/TodaySchema.h b/samples/unified/TodaySchema.h index e1e6ff3b..a99341ca 100644 --- a/samples/unified/TodaySchema.h +++ b/samples/unified/TodaySchema.h @@ -6,6 +6,7 @@ #ifndef TODAYSCHEMA_H #define TODAYSCHEMA_H +#include "graphqlservice/GraphQLSchema.h" #include "graphqlservice/GraphQLService.h" #include @@ -13,12 +14,6 @@ #include namespace graphql { -namespace introspection { - -class Schema; - -} /* namespace introspection */ - namespace today { enum class TaskState @@ -83,22 +78,22 @@ class Query virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveAppointments(service::ResolverParams&& params); - std::future resolveTasks(service::ResolverParams&& params); - std::future resolveUnreadCounts(service::ResolverParams&& params); - std::future resolveAppointmentsById(service::ResolverParams&& params); - std::future resolveTasksById(service::ResolverParams&& params); - std::future resolveUnreadCountsById(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); - std::future resolveUnimplemented(service::ResolverParams&& params); - std::future resolveExpensive(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; + std::future resolveNode(service::ResolverParams&& params); + std::future resolveAppointments(service::ResolverParams&& params); + std::future resolveTasks(service::ResolverParams&& params); + std::future resolveUnreadCounts(service::ResolverParams&& params); + std::future resolveAppointmentsById(service::ResolverParams&& params); + std::future resolveTasksById(service::ResolverParams&& params); + std::future resolveUnreadCountsById(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + std::future resolveUnimplemented(service::ResolverParams&& params); + std::future resolveExpensive(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_schema(service::ResolverParams&& params); + std::future resolve_type(service::ResolverParams&& params); + + std::shared_ptr _schema; }; class PageInfo @@ -112,10 +107,10 @@ class PageInfo virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; private: - std::future resolveHasNextPage(service::ResolverParams&& params); - std::future resolveHasPreviousPage(service::ResolverParams&& params); + std::future resolveHasNextPage(service::ResolverParams&& params); + std::future resolveHasPreviousPage(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class AppointmentEdge @@ -129,10 +124,10 @@ class AppointmentEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class AppointmentConnection @@ -146,10 +141,10 @@ class AppointmentConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class TaskEdge @@ -163,10 +158,10 @@ class TaskEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class TaskConnection @@ -180,10 +175,10 @@ class TaskConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class FolderEdge @@ -197,10 +192,10 @@ class FolderEdge virtual service::FieldResult getCursor(service::FieldParams&& params) const; private: - std::future resolveNode(service::ResolverParams&& params); - std::future resolveCursor(service::ResolverParams&& params); + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class FolderConnection @@ -214,10 +209,10 @@ class FolderConnection virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; private: - std::future resolvePageInfo(service::ResolverParams&& params); - std::future resolveEdges(service::ResolverParams&& params); + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class CompleteTaskPayload @@ -231,10 +226,10 @@ class CompleteTaskPayload virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; private: - std::future resolveTask(service::ResolverParams&& params); - std::future resolveClientMutationId(service::ResolverParams&& params); + std::future resolveTask(service::ResolverParams&& params); + std::future resolveClientMutationId(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Mutation @@ -248,10 +243,10 @@ class Mutation virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; private: - std::future resolveCompleteTask(service::ResolverParams&& params); - std::future resolveSetFloat(service::ResolverParams&& params); + std::future resolveCompleteTask(service::ResolverParams&& params); + std::future resolveSetFloat(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Subscription @@ -265,10 +260,10 @@ class Subscription virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; private: - std::future resolveNextAppointmentChange(service::ResolverParams&& params); - std::future resolveNodeChange(service::ResolverParams&& params); + std::future resolveNextAppointmentChange(service::ResolverParams&& params); + std::future resolveNodeChange(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Appointment @@ -283,14 +278,16 @@ class Appointment virtual service::FieldResult> getWhen(service::FieldParams&& params) const; virtual service::FieldResult> getSubject(service::FieldParams&& params) const; virtual service::FieldResult getIsNow(service::FieldParams&& params) const; + virtual service::FieldResult> getForceError(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveWhen(service::ResolverParams&& params); - std::future resolveSubject(service::ResolverParams&& params); - std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveWhen(service::ResolverParams&& params); + std::future resolveSubject(service::ResolverParams&& params); + std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveForceError(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Task @@ -306,11 +303,11 @@ class Task virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveTitle(service::ResolverParams&& params); - std::future resolveIsComplete(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveTitle(service::ResolverParams&& params); + std::future resolveIsComplete(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Folder @@ -326,11 +323,11 @@ class Folder virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); - std::future resolveName(service::ResolverParams&& params); - std::future resolveUnreadCount(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveUnreadCount(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class NestedType @@ -344,10 +341,10 @@ class NestedType virtual service::FieldResult> getNested(service::FieldParams&& params) const; private: - std::future resolveDepth(service::ResolverParams&& params); - std::future resolveNested(service::ResolverParams&& params); + std::future resolveDepth(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Expensive @@ -360,9 +357,9 @@ class Expensive virtual service::FieldResult getOrder(service::FieldParams&& params) const; private: - std::future resolveOrder(service::ResolverParams&& params); + std::future resolveOrder(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace object */ @@ -379,7 +376,7 @@ class Operations std::shared_ptr _subscription; }; -void AddTypesToSchema(const std::shared_ptr& schema); +std::shared_ptr GetSchema(); } /* namespace today */ } /* namespace graphql */ diff --git a/samples/unified_nointrospection/TodaySchema.cpp b/samples/unified_nointrospection/TodaySchema.cpp new file mode 100644 index 00000000..c88a0cd6 --- /dev/null +++ b/samples/unified_nointrospection/TodaySchema.cpp @@ -0,0 +1,1278 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "TodaySchema.h" + +#include "graphqlservice/introspection/Introspection.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std::literals; + +namespace graphql { +namespace service { + +static const std::array s_namesTaskState = { + "New", + "Started", + "Complete", + "Unassigned" +}; + +template <> +today::TaskState ModifiedArgument::convert(const response::Value& value) +{ + if (!value.maybe_enum()) + { + throw service::schema_exception { { "not a valid TaskState value" } }; + } + + auto itr = std::find(s_namesTaskState.cbegin(), s_namesTaskState.cend(), value.get()); + + if (itr == s_namesTaskState.cend()) + { + throw service::schema_exception { { "not a valid TaskState value" } }; + } + + return static_cast(itr - s_namesTaskState.cbegin()); +} + +template <> +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +{ + return resolve(std::move(result), std::move(params), + [](today::TaskState&& value, const ResolverParams&) + { + response::Value result(response::Type::EnumValue); + + result.set(std::string(s_namesTaskState[static_cast(value)])); + + return result; + }); +} + +template <> +today::CompleteTaskInput ModifiedArgument::convert(const response::Value& value) +{ + const auto defaultValue = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = response::Value(true); + values.emplace_back("isComplete", std::move(entry)); + + return values; + }(); + + auto valueId = service::ModifiedArgument::require("id", value); + auto pairIsComplete = service::ModifiedArgument::find("isComplete", value); + auto valueIsComplete = (pairIsComplete.second + ? std::move(pairIsComplete.first) + : service::ModifiedArgument::require("isComplete", defaultValue)); + auto valueClientMutationId = service::ModifiedArgument::require("clientMutationId", value); + + return { + std::move(valueId), + std::move(valueIsComplete), + std::move(valueClientMutationId) + }; +} + +} /* namespace service */ + +namespace today { +namespace object { + +Query::Query() + : service::Object({ + "Query" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(appointments)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointments(std::move(params)); } }, + { R"gql(appointmentsById)gql"sv, [this](service::ResolverParams&& params) { return resolveAppointmentsById(std::move(params)); } }, + { R"gql(expensive)gql"sv, [this](service::ResolverParams&& params) { return resolveExpensive(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } }, + { R"gql(tasks)gql"sv, [this](service::ResolverParams&& params) { return resolveTasks(std::move(params)); } }, + { R"gql(tasksById)gql"sv, [this](service::ResolverParams&& params) { return resolveTasksById(std::move(params)); } }, + { R"gql(unimplemented)gql"sv, [this](service::ResolverParams&& params) { return resolveUnimplemented(std::move(params)); } }, + { R"gql(unreadCounts)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCounts(std::move(params)); } }, + { R"gql(unreadCountsById)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCountsById(std::move(params)); } } + }) +{ +} + +service::FieldResult> Query::getNode(service::FieldParams&&, response::IdType&&) const +{ + throw std::runtime_error(R"ex(Query::getNode is not implemented)ex"); +} + +std::future Query::resolveNode(service::ResolverParams&& params) +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getAppointments(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getAppointments is not implemented)ex"); +} + +std::future Query::resolveAppointments(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getAppointments(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getTasks(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getTasks is not implemented)ex"); +} + +std::future Query::resolveTasks(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getTasks(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getUnreadCounts(service::FieldParams&&, std::optional&&, std::optional&&, std::optional&&, std::optional&&) const +{ + throw std::runtime_error(R"ex(Query::getUnreadCounts is not implemented)ex"); +} + +std::future Query::resolveUnreadCounts(service::ResolverParams&& params) +{ + auto argFirst = service::ModifiedArgument::require("first", params.arguments); + auto argAfter = service::ModifiedArgument::require("after", params.arguments); + auto argLast = service::ModifiedArgument::require("last", params.arguments); + auto argBefore = service::ModifiedArgument::require("before", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCounts(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argFirst), std::move(argAfter), std::move(argLast), std::move(argBefore)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getAppointmentsById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getAppointmentsById is not implemented)ex"); +} + +std::future Query::resolveAppointmentsById(service::ResolverParams&& params) +{ + const auto defaultArguments = []() + { + response::Value values(response::Type::Map); + response::Value entry; + + entry = []() + { + response::Value elements(response::Type::List); + response::Value entry; + + entry = response::Value(std::string(R"gql(ZmFrZUFwcG9pbnRtZW50SWQ=)gql")); + elements.emplace_back(std::move(entry)); + return elements; + }(); + values.emplace_back("ids", std::move(entry)); + + return values; + }(); + + auto pairIds = service::ModifiedArgument::find("ids", params.arguments); + auto argIds = (pairIds.second + ? std::move(pairIds.first) + : service::ModifiedArgument::require("ids", defaultArguments)); + std::unique_lock resolverLock(_resolverMutex); + auto result = getAppointmentsById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getTasksById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getTasksById is not implemented)ex"); +} + +std::future Query::resolveTasksById(service::ResolverParams&& params) +{ + auto argIds = service::ModifiedArgument::require("ids", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getTasksById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getUnreadCountsById(service::FieldParams&&, std::vector&&) const +{ + throw std::runtime_error(R"ex(Query::getUnreadCountsById is not implemented)ex"); +} + +std::future Query::resolveUnreadCountsById(service::ResolverParams&& params) +{ + auto argIds = service::ModifiedArgument::require("ids", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCountsById(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argIds)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Query::getNested(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getNested is not implemented)ex"); +} + +std::future Query::resolveNested(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Query::getUnimplemented(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getUnimplemented is not implemented)ex"); +} + +std::future Query::resolveUnimplemented(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnimplemented(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>> Query::getExpensive(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Query::getExpensive is not implemented)ex"); +} + +std::future Query::resolveExpensive(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getExpensive(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Query::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); +} + +PageInfo::PageInfo() + : service::Object({ + "PageInfo" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(hasNextPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasNextPage(std::move(params)); } }, + { R"gql(hasPreviousPage)gql"sv, [this](service::ResolverParams&& params) { return resolveHasPreviousPage(std::move(params)); } } + }) +{ +} + +service::FieldResult PageInfo::getHasNextPage(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(PageInfo::getHasNextPage is not implemented)ex"); +} + +std::future PageInfo::resolveHasNextPage(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getHasNextPage(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult PageInfo::getHasPreviousPage(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(PageInfo::getHasPreviousPage is not implemented)ex"); +} + +std::future PageInfo::resolveHasPreviousPage(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getHasPreviousPage(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future PageInfo::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(PageInfo)gql" }, std::move(params)); +} + +AppointmentEdge::AppointmentEdge() + : service::Object({ + "AppointmentEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> AppointmentEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentEdge::getNode is not implemented)ex"); +} + +std::future AppointmentEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult AppointmentEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentEdge::getCursor is not implemented)ex"); +} + +std::future AppointmentEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future AppointmentEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentEdge)gql" }, std::move(params)); +} + +AppointmentConnection::AppointmentConnection() + : service::Object({ + "AppointmentConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> AppointmentConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentConnection::getPageInfo is not implemented)ex"); +} + +std::future AppointmentConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> AppointmentConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(AppointmentConnection::getEdges is not implemented)ex"); +} + +std::future AppointmentConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future AppointmentConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(AppointmentConnection)gql" }, std::move(params)); +} + +TaskEdge::TaskEdge() + : service::Object({ + "TaskEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> TaskEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskEdge::getNode is not implemented)ex"); +} + +std::future TaskEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult TaskEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskEdge::getCursor is not implemented)ex"); +} + +std::future TaskEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future TaskEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(TaskEdge)gql" }, std::move(params)); +} + +TaskConnection::TaskConnection() + : service::Object({ + "TaskConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> TaskConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskConnection::getPageInfo is not implemented)ex"); +} + +std::future TaskConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> TaskConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(TaskConnection::getEdges is not implemented)ex"); +} + +std::future TaskConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future TaskConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(TaskConnection)gql" }, std::move(params)); +} + +FolderEdge::FolderEdge() + : service::Object({ + "FolderEdge" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(cursor)gql"sv, [this](service::ResolverParams&& params) { return resolveCursor(std::move(params)); } }, + { R"gql(node)gql"sv, [this](service::ResolverParams&& params) { return resolveNode(std::move(params)); } } + }) +{ +} + +service::FieldResult> FolderEdge::getNode(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderEdge::getNode is not implemented)ex"); +} + +std::future FolderEdge::resolveNode(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNode(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult FolderEdge::getCursor(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderEdge::getCursor is not implemented)ex"); +} + +std::future FolderEdge::resolveCursor(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getCursor(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future FolderEdge::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(FolderEdge)gql" }, std::move(params)); +} + +FolderConnection::FolderConnection() + : service::Object({ + "FolderConnection" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(edges)gql"sv, [this](service::ResolverParams&& params) { return resolveEdges(std::move(params)); } }, + { R"gql(pageInfo)gql"sv, [this](service::ResolverParams&& params) { return resolvePageInfo(std::move(params)); } } + }) +{ +} + +service::FieldResult> FolderConnection::getPageInfo(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderConnection::getPageInfo is not implemented)ex"); +} + +std::future FolderConnection::resolvePageInfo(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getPageInfo(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult>>> FolderConnection::getEdges(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(FolderConnection::getEdges is not implemented)ex"); +} + +std::future FolderConnection::resolveEdges(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getEdges(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future FolderConnection::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(FolderConnection)gql" }, std::move(params)); +} + +CompleteTaskPayload::CompleteTaskPayload() + : service::Object({ + "CompleteTaskPayload" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(clientMutationId)gql"sv, [this](service::ResolverParams&& params) { return resolveClientMutationId(std::move(params)); } }, + { R"gql(task)gql"sv, [this](service::ResolverParams&& params) { return resolveTask(std::move(params)); } } + }) +{ +} + +service::FieldResult> CompleteTaskPayload::getTask(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(CompleteTaskPayload::getTask is not implemented)ex"); +} + +std::future CompleteTaskPayload::resolveTask(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getTask(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> CompleteTaskPayload::getClientMutationId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(CompleteTaskPayload::getClientMutationId is not implemented)ex"); +} + +std::future CompleteTaskPayload::resolveClientMutationId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getClientMutationId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future CompleteTaskPayload::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(CompleteTaskPayload)gql" }, std::move(params)); +} + +Mutation::Mutation() + : service::Object({ + "Mutation" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(completeTask)gql"sv, [this](service::ResolverParams&& params) { return resolveCompleteTask(std::move(params)); } }, + { R"gql(setFloat)gql"sv, [this](service::ResolverParams&& params) { return resolveSetFloat(std::move(params)); } } + }) +{ +} + +service::FieldResult> Mutation::applyCompleteTask(service::FieldParams&&, CompleteTaskInput&&) const +{ + throw std::runtime_error(R"ex(Mutation::applyCompleteTask is not implemented)ex"); +} + +std::future Mutation::resolveCompleteTask(service::ResolverParams&& params) +{ + auto argInput = service::ModifiedArgument::require("input", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = applyCompleteTask(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argInput)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Mutation::applySetFloat(service::FieldParams&&, response::FloatType&&) const +{ + throw std::runtime_error(R"ex(Mutation::applySetFloat is not implemented)ex"); +} + +std::future Mutation::resolveSetFloat(service::ResolverParams&& params) +{ + auto argValue = service::ModifiedArgument::require("value", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = applySetFloat(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argValue)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Mutation::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); +} + +Subscription::Subscription() + : service::Object({ + "Subscription" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(nextAppointmentChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNextAppointmentChange(std::move(params)); } }, + { R"gql(nodeChange)gql"sv, [this](service::ResolverParams&& params) { return resolveNodeChange(std::move(params)); } } + }) +{ +} + +service::FieldResult> Subscription::getNextAppointmentChange(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Subscription::getNextAppointmentChange is not implemented)ex"); +} + +std::future Subscription::resolveNextAppointmentChange(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNextAppointmentChange(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Subscription::getNodeChange(service::FieldParams&&, response::IdType&&) const +{ + throw std::runtime_error(R"ex(Subscription::getNodeChange is not implemented)ex"); +} + +std::future Subscription::resolveNodeChange(service::ResolverParams&& params) +{ + auto argId = service::ModifiedArgument::require("id", params.arguments); + std::unique_lock resolverLock(_resolverMutex); + auto result = getNodeChange(service::FieldParams(params, std::move(params.fieldDirectives)), std::move(argId)); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Subscription::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); +} + +Appointment::Appointment() + : service::Object({ + "Node", + "UnionType", + "Appointment" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(forceError)gql"sv, [this](service::ResolverParams&& params) { return resolveForceError(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(isNow)gql"sv, [this](service::ResolverParams&& params) { return resolveIsNow(std::move(params)); } }, + { R"gql(subject)gql"sv, [this](service::ResolverParams&& params) { return resolveSubject(std::move(params)); } }, + { R"gql(when)gql"sv, [this](service::ResolverParams&& params) { return resolveWhen(std::move(params)); } } + }) +{ +} + +service::FieldResult Appointment::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getId is not implemented)ex"); +} + +std::future Appointment::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getWhen(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getWhen is not implemented)ex"); +} + +std::future Appointment::resolveWhen(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getWhen(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getSubject(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getSubject is not implemented)ex"); +} + +std::future Appointment::resolveSubject(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getSubject(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Appointment::getIsNow(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getIsNow is not implemented)ex"); +} + +std::future Appointment::resolveIsNow(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getIsNow(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Appointment::getForceError(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Appointment::getForceError is not implemented)ex"); +} + +std::future Appointment::resolveForceError(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getForceError(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Appointment::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Appointment)gql" }, std::move(params)); +} + +Task::Task() + : service::Object({ + "Node", + "UnionType", + "Task" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(isComplete)gql"sv, [this](service::ResolverParams&& params) { return resolveIsComplete(std::move(params)); } }, + { R"gql(title)gql"sv, [this](service::ResolverParams&& params) { return resolveTitle(std::move(params)); } } + }) +{ +} + +service::FieldResult Task::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getId is not implemented)ex"); +} + +std::future Task::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Task::getTitle(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getTitle is not implemented)ex"); +} + +std::future Task::resolveTitle(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getTitle(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Task::getIsComplete(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Task::getIsComplete is not implemented)ex"); +} + +std::future Task::resolveIsComplete(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getIsComplete(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Task::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Task)gql" }, std::move(params)); +} + +Folder::Folder() + : service::Object({ + "Node", + "UnionType", + "Folder" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(id)gql"sv, [this](service::ResolverParams&& params) { return resolveId(std::move(params)); } }, + { R"gql(name)gql"sv, [this](service::ResolverParams&& params) { return resolveName(std::move(params)); } }, + { R"gql(unreadCount)gql"sv, [this](service::ResolverParams&& params) { return resolveUnreadCount(std::move(params)); } } + }) +{ +} + +service::FieldResult Folder::getId(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getId is not implemented)ex"); +} + +std::future Folder::resolveId(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> Folder::getName(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getName is not implemented)ex"); +} + +std::future Folder::resolveName(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult Folder::getUnreadCount(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Folder::getUnreadCount is not implemented)ex"); +} + +std::future Folder::resolveUnreadCount(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getUnreadCount(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Folder::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Folder)gql" }, std::move(params)); +} + +NestedType::NestedType() + : service::Object({ + "NestedType" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(depth)gql"sv, [this](service::ResolverParams&& params) { return resolveDepth(std::move(params)); } }, + { R"gql(nested)gql"sv, [this](service::ResolverParams&& params) { return resolveNested(std::move(params)); } } + }) +{ +} + +service::FieldResult NestedType::getDepth(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(NestedType::getDepth is not implemented)ex"); +} + +std::future NestedType::resolveDepth(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getDepth(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +service::FieldResult> NestedType::getNested(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(NestedType::getNested is not implemented)ex"); +} + +std::future NestedType::resolveNested(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getNested(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future NestedType::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(NestedType)gql" }, std::move(params)); +} + +Expensive::Expensive() + : service::Object({ + "Expensive" + }, { + { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } }, + { R"gql(order)gql"sv, [this](service::ResolverParams&& params) { return resolveOrder(std::move(params)); } } + }) +{ +} + +service::FieldResult Expensive::getOrder(service::FieldParams&&) const +{ + throw std::runtime_error(R"ex(Expensive::getOrder is not implemented)ex"); +} + +std::future Expensive::resolveOrder(service::ResolverParams&& params) +{ + std::unique_lock resolverLock(_resolverMutex); + auto result = getOrder(service::FieldParams(params, std::move(params.fieldDirectives))); + resolverLock.unlock(); + + return service::ModifiedResult::convert(std::move(result), std::move(params)); +} + +std::future Expensive::resolve_typename(service::ResolverParams&& params) +{ + return service::ModifiedResult::convert(response::StringType{ R"gql(Expensive)gql" }, std::move(params)); +} + +} /* namespace object */ + +Operations::Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription) + : service::Request({ + { "query", query }, + { "mutation", mutation }, + { "subscription", subscription } + }, GetSchema()) + , _query(std::move(query)) + , _mutation(std::move(mutation)) + , _subscription(std::move(subscription)) +{ +} + +void AddTypesToSchema(const std::shared_ptr& schema) +{ + schema->AddType(R"gql(ItemCursor)gql"sv, schema::ScalarType::Make(R"gql(ItemCursor)gql"sv, R"md()md")); + schema->AddType(R"gql(DateTime)gql"sv, schema::ScalarType::Make(R"gql(DateTime)gql"sv, R"md()md")); + auto typeTaskState = schema::EnumType::Make(R"gql(TaskState)gql"sv, R"md()md"sv); + schema->AddType(R"gql(TaskState)gql"sv, typeTaskState); + auto typeCompleteTaskInput = schema::InputObjectType::Make(R"gql(CompleteTaskInput)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CompleteTaskInput)gql"sv, typeCompleteTaskInput); + auto typeUnionType = schema::UnionType::Make(R"gql(UnionType)gql"sv, R"md()md"sv); + schema->AddType(R"gql(UnionType)gql"sv, typeUnionType); + auto typeNode = schema::InterfaceType::Make(R"gql(Node)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Node)gql"sv, typeNode); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md()md"); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typePageInfo = schema::ObjectType::Make(R"gql(PageInfo)gql"sv, R"md()md"); + schema->AddType(R"gql(PageInfo)gql"sv, typePageInfo); + auto typeAppointmentEdge = schema::ObjectType::Make(R"gql(AppointmentEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentEdge)gql"sv, typeAppointmentEdge); + auto typeAppointmentConnection = schema::ObjectType::Make(R"gql(AppointmentConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(AppointmentConnection)gql"sv, typeAppointmentConnection); + auto typeTaskEdge = schema::ObjectType::Make(R"gql(TaskEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskEdge)gql"sv, typeTaskEdge); + auto typeTaskConnection = schema::ObjectType::Make(R"gql(TaskConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(TaskConnection)gql"sv, typeTaskConnection); + auto typeFolderEdge = schema::ObjectType::Make(R"gql(FolderEdge)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderEdge)gql"sv, typeFolderEdge); + auto typeFolderConnection = schema::ObjectType::Make(R"gql(FolderConnection)gql"sv, R"md()md"); + schema->AddType(R"gql(FolderConnection)gql"sv, typeFolderConnection); + auto typeCompleteTaskPayload = schema::ObjectType::Make(R"gql(CompleteTaskPayload)gql"sv, R"md()md"); + schema->AddType(R"gql(CompleteTaskPayload)gql"sv, typeCompleteTaskPayload); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md()md"); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md()md"); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeAppointment = schema::ObjectType::Make(R"gql(Appointment)gql"sv, R"md()md"); + schema->AddType(R"gql(Appointment)gql"sv, typeAppointment); + auto typeTask = schema::ObjectType::Make(R"gql(Task)gql"sv, R"md()md"); + schema->AddType(R"gql(Task)gql"sv, typeTask); + auto typeFolder = schema::ObjectType::Make(R"gql(Folder)gql"sv, R"md()md"); + schema->AddType(R"gql(Folder)gql"sv, typeFolder); + auto typeNestedType = schema::ObjectType::Make(R"gql(NestedType)gql"sv, R"md()md"); + schema->AddType(R"gql(NestedType)gql"sv, typeNestedType); + auto typeExpensive = schema::ObjectType::Make(R"gql(Expensive)gql"sv, R"md()md"); + schema->AddType(R"gql(Expensive)gql"sv, typeExpensive); + + typeTaskState->AddEnumValues({ + { service::s_namesTaskState[static_cast(today::TaskState::New)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Started)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Complete)], R"md()md"sv, std::nullopt }, + { service::s_namesTaskState[static_cast(today::TaskState::Unassigned)], R"md()md"sv, std::make_optional(R"md(Need to deprecate an [enum value](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv) } + }); + + typeCompleteTaskInput->AddInputValues({ + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv), + schema::InputValue::Make(R"gql(isComplete)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql(true)gql"sv), + schema::InputValue::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + }); + + typeUnionType->AddPossibleTypes({ + schema->LookupType(R"gql(Appointment)gql"sv), + schema->LookupType(R"gql(Task)gql"sv), + schema->LookupType(R"gql(Folder)gql"sv) + }); + + typeNode->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + }); + + typeQuery->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Node"), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointments)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("AppointmentConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(tasks)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("TaskConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCounts)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("FolderConnection")), { + schema::InputValue::Make(R"gql(first)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(after)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(last)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(before)gql"sv, R"md()md"sv, schema->LookupType("ItemCursor"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(appointmentsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Appointment"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql(["ZmFrZUFwcG9pbnRtZW50SWQ="])gql"sv) + }), + schema::Field::Make(R"gql(tasksById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Task"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(unreadCountsById)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Folder"))), { + schema::InputValue::Make(R"gql(ids)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))), + schema::Field::Make(R"gql(unimplemented)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(expensive)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Expensive"))))) + }); + typePageInfo->AddFields({ + schema::Field::Make(R"gql(hasNextPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(hasPreviousPage)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + }); + typeAppointmentEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Appointment")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); + typeAppointmentConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("AppointmentEdge"))) + }); + typeTaskEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); + typeTaskConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("TaskEdge"))) + }); + typeFolderEdge->AddFields({ + schema::Field::Make(R"gql(node)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Folder")), + schema::Field::Make(R"gql(cursor)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ItemCursor"))) + }); + typeFolderConnection->AddFields({ + schema::Field::Make(R"gql(pageInfo)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("PageInfo"))), + schema::Field::Make(R"gql(edges)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("FolderEdge"))) + }); + typeCompleteTaskPayload->AddFields({ + schema::Field::Make(R"gql(task)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Task")), + schema::Field::Make(R"gql(clientMutationId)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) + }); + typeMutation->AddFields({ + schema::Field::Make(R"gql(completeTask)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskPayload")), { + schema::InputValue::Make(R"gql(input)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CompleteTaskInput")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(setFloat)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), { + schema::InputValue::Make(R"gql(value)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Float")), R"gql()gql"sv) + }) + }); + typeSubscription->AddFields({ + schema::Field::Make(R"gql(nextAppointmentChange)gql"sv, R"md()md"sv, std::make_optional(R"md(Need to deprecate a [field](https://facebook.github.io/graphql/June2018/#sec-Deprecation))md"sv), schema->LookupType("Appointment")), + schema::Field::Make(R"gql(nodeChange)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Node")), { + schema::InputValue::Make(R"gql(id)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID")), R"gql()gql"sv) + }) + }); + typeAppointment->AddInterfaces({ + typeNode + }); + typeAppointment->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(when)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("DateTime")), + schema::Field::Make(R"gql(subject)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isNow)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), + schema::Field::Make(R"gql(forceError)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) + }); + typeTask->AddInterfaces({ + typeNode + }); + typeTask->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(title)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(isComplete)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + }); + typeFolder->AddInterfaces({ + typeNode + }); + typeFolder->AddFields({ + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))), + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(unreadCount)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + }); + typeNestedType->AddFields({ + schema::Field::Make(R"gql(depth)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), + schema::Field::Make(R"gql(nested)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("NestedType"))) + }); + typeExpensive->AddFields({ + schema::Field::Make(R"gql(order)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))) + }); + + schema->AddDirective(schema::Directive::Make(R"gql(id)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD_DEFINITION + })); + schema->AddDirective(schema::Directive::Make(R"gql(subscriptionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::SUBSCRIPTION + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(queryTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::QUERY + }, { + schema::InputValue::Make(R"gql(query)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fieldTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FIELD + }, { + schema::InputValue::Make(R"gql(field)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentDefinitionTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_DEFINITION + }, { + schema::InputValue::Make(R"gql(fragmentDefinition)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(fragmentSpreadTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::FRAGMENT_SPREAD + }, { + schema::InputValue::Make(R"gql(fragmentSpread)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + schema->AddDirective(schema::Directive::Make(R"gql(inlineFragmentTag)gql"sv, R"md()md"sv, { + introspection::DirectiveLocation::INLINE_FRAGMENT + }, { + schema::InputValue::Make(R"gql(inlineFragment)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String")), R"gql()gql"sv) + })); + + schema->AddQueryType(typeQuery); + schema->AddMutationType(typeMutation); + schema->AddSubscriptionType(typeSubscription); +} + +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(true); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + +} /* namespace today */ +} /* namespace graphql */ diff --git a/samples/unified_nointrospection/TodaySchema.h b/samples/unified_nointrospection/TodaySchema.h new file mode 100644 index 00000000..fab48a2a --- /dev/null +++ b/samples/unified_nointrospection/TodaySchema.h @@ -0,0 +1,380 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#pragma once + +#ifndef TODAYSCHEMA_H +#define TODAYSCHEMA_H + +#include "graphqlservice/GraphQLSchema.h" +#include "graphqlservice/GraphQLService.h" + +#include +#include +#include + +namespace graphql { +namespace today { + +enum class TaskState +{ + New, + Started, + Complete, + Unassigned +}; + +struct CompleteTaskInput +{ + response::IdType id; + std::optional isComplete; + std::optional clientMutationId; +}; + +namespace object { + +class Query; +class PageInfo; +class AppointmentEdge; +class AppointmentConnection; +class TaskEdge; +class TaskConnection; +class FolderEdge; +class FolderConnection; +class CompleteTaskPayload; +class Mutation; +class Subscription; +class Appointment; +class Task; +class Folder; +class NestedType; +class Expensive; + +} /* namespace object */ + +struct Node +{ + virtual service::FieldResult getId(service::FieldParams&& params) const = 0; +}; + +namespace object { + +class Query + : public service::Object +{ +protected: + explicit Query(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params, response::IdType&& idArg) const; + virtual service::FieldResult> getAppointments(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult> getTasks(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult> getUnreadCounts(service::FieldParams&& params, std::optional&& firstArg, std::optional&& afterArg, std::optional&& lastArg, std::optional&& beforeArg) const; + virtual service::FieldResult>> getAppointmentsById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult>> getTasksById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult>> getUnreadCountsById(service::FieldParams&& params, std::vector&& idsArg) const; + virtual service::FieldResult> getNested(service::FieldParams&& params) const; + virtual service::FieldResult getUnimplemented(service::FieldParams&& params) const; + virtual service::FieldResult>> getExpensive(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveAppointments(service::ResolverParams&& params); + std::future resolveTasks(service::ResolverParams&& params); + std::future resolveUnreadCounts(service::ResolverParams&& params); + std::future resolveAppointmentsById(service::ResolverParams&& params); + std::future resolveTasksById(service::ResolverParams&& params); + std::future resolveUnreadCountsById(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + std::future resolveUnimplemented(service::ResolverParams&& params); + std::future resolveExpensive(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class PageInfo + : public service::Object +{ +protected: + explicit PageInfo(); + +public: + virtual service::FieldResult getHasNextPage(service::FieldParams&& params) const; + virtual service::FieldResult getHasPreviousPage(service::FieldParams&& params) const; + +private: + std::future resolveHasNextPage(service::ResolverParams&& params); + std::future resolveHasPreviousPage(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class AppointmentEdge + : public service::Object +{ +protected: + explicit AppointmentEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class AppointmentConnection + : public service::Object +{ +protected: + explicit AppointmentConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class TaskEdge + : public service::Object +{ +protected: + explicit TaskEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class TaskConnection + : public service::Object +{ +protected: + explicit TaskConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class FolderEdge + : public service::Object +{ +protected: + explicit FolderEdge(); + +public: + virtual service::FieldResult> getNode(service::FieldParams&& params) const; + virtual service::FieldResult getCursor(service::FieldParams&& params) const; + +private: + std::future resolveNode(service::ResolverParams&& params); + std::future resolveCursor(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class FolderConnection + : public service::Object +{ +protected: + explicit FolderConnection(); + +public: + virtual service::FieldResult> getPageInfo(service::FieldParams&& params) const; + virtual service::FieldResult>>> getEdges(service::FieldParams&& params) const; + +private: + std::future resolvePageInfo(service::ResolverParams&& params); + std::future resolveEdges(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class CompleteTaskPayload + : public service::Object +{ +protected: + explicit CompleteTaskPayload(); + +public: + virtual service::FieldResult> getTask(service::FieldParams&& params) const; + virtual service::FieldResult> getClientMutationId(service::FieldParams&& params) const; + +private: + std::future resolveTask(service::ResolverParams&& params); + std::future resolveClientMutationId(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Mutation + : public service::Object +{ +protected: + explicit Mutation(); + +public: + virtual service::FieldResult> applyCompleteTask(service::FieldParams&& params, CompleteTaskInput&& inputArg) const; + virtual service::FieldResult applySetFloat(service::FieldParams&& params, response::FloatType&& valueArg) const; + +private: + std::future resolveCompleteTask(service::ResolverParams&& params); + std::future resolveSetFloat(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Subscription + : public service::Object +{ +protected: + explicit Subscription(); + +public: + virtual service::FieldResult> getNextAppointmentChange(service::FieldParams&& params) const; + virtual service::FieldResult> getNodeChange(service::FieldParams&& params, response::IdType&& idArg) const; + +private: + std::future resolveNextAppointmentChange(service::ResolverParams&& params); + std::future resolveNodeChange(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Appointment + : public service::Object + , public Node +{ +protected: + explicit Appointment(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getWhen(service::FieldParams&& params) const; + virtual service::FieldResult> getSubject(service::FieldParams&& params) const; + virtual service::FieldResult getIsNow(service::FieldParams&& params) const; + virtual service::FieldResult> getForceError(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveWhen(service::ResolverParams&& params); + std::future resolveSubject(service::ResolverParams&& params); + std::future resolveIsNow(service::ResolverParams&& params); + std::future resolveForceError(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Task + : public service::Object + , public Node +{ +protected: + explicit Task(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getTitle(service::FieldParams&& params) const; + virtual service::FieldResult getIsComplete(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveTitle(service::ResolverParams&& params); + std::future resolveIsComplete(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Folder + : public service::Object + , public Node +{ +protected: + explicit Folder(); + +public: + virtual service::FieldResult getId(service::FieldParams&& params) const override; + virtual service::FieldResult> getName(service::FieldParams&& params) const; + virtual service::FieldResult getUnreadCount(service::FieldParams&& params) const; + +private: + std::future resolveId(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveUnreadCount(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class NestedType + : public service::Object +{ +protected: + explicit NestedType(); + +public: + virtual service::FieldResult getDepth(service::FieldParams&& params) const; + virtual service::FieldResult> getNested(service::FieldParams&& params) const; + +private: + std::future resolveDepth(service::ResolverParams&& params); + std::future resolveNested(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +class Expensive + : public service::Object +{ +protected: + explicit Expensive(); + +public: + virtual service::FieldResult getOrder(service::FieldParams&& params) const; + +private: + std::future resolveOrder(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); +}; + +} /* namespace object */ + +class Operations + : public service::Request +{ +public: + explicit Operations(std::shared_ptr query, std::shared_ptr mutation, std::shared_ptr subscription); + +private: + std::shared_ptr _query; + std::shared_ptr _mutation; + std::shared_ptr _subscription; +}; + +std::shared_ptr GetSchema(); + +} /* namespace today */ +} /* namespace graphql */ + +#endif // TODAYSCHEMA_H diff --git a/samples/validation/ValidationSchema.cpp b/samples/validation/ValidationSchema.cpp index 19f5157f..dd4f6767 100644 --- a/samples/validation/ValidationSchema.cpp +++ b/samples/validation/ValidationSchema.cpp @@ -3,7 +3,7 @@ #include "ValidationSchema.h" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -44,7 +44,7 @@ validation::DogCommand ModifiedArgument::convert(const r } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](validation::DogCommand&& value, const ResolverParams&) @@ -80,7 +80,7 @@ validation::CatCommand ModifiedArgument::convert(const r } template <> -std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) +std::future ModifiedResult::convert(service::FieldResult&& result, ResolverParams&& params) { return resolve(std::move(result), std::move(params), [](validation::CatCommand&& value, const ResolverParams&) @@ -125,10 +125,8 @@ Query::Query() { R"gql(human)gql"sv, [this](service::ResolverParams&& params) { return resolveHuman(std::move(params)); } }, { R"gql(pet)gql"sv, [this](service::ResolverParams&& params) { return resolvePet(std::move(params)); } } }) - , _schema(std::make_shared()) + , _schema(GetSchema()) { - introspection::AddTypesToSchema(_schema); - validation::AddTypesToSchema(_schema); } service::FieldResult> Query::getDog(service::FieldParams&&) const @@ -136,7 +134,7 @@ service::FieldResult> Query::getDog(service::FieldParams&&) throw std::runtime_error(R"ex(Query::getDog is not implemented)ex"); } -std::future Query::resolveDog(service::ResolverParams&& params) +std::future Query::resolveDog(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDog(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -150,7 +148,7 @@ service::FieldResult> Query::getHuman(service::FieldParam throw std::runtime_error(R"ex(Query::getHuman is not implemented)ex"); } -std::future Query::resolveHuman(service::ResolverParams&& params) +std::future Query::resolveHuman(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHuman(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -164,7 +162,7 @@ service::FieldResult> Query::getPet(service::Fi throw std::runtime_error(R"ex(Query::getPet is not implemented)ex"); } -std::future Query::resolvePet(service::ResolverParams&& params) +std::future Query::resolvePet(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPet(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -178,7 +176,7 @@ service::FieldResult> Query::getCatOrDog(servic throw std::runtime_error(R"ex(Query::getCatOrDog is not implemented)ex"); } -std::future Query::resolveCatOrDog(service::ResolverParams&& params) +std::future Query::resolveCatOrDog(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getCatOrDog(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -192,7 +190,7 @@ service::FieldResult> Query::getArguments(service::Fi throw std::runtime_error(R"ex(Query::getArguments is not implemented)ex"); } -std::future Query::resolveArguments(service::ResolverParams&& params) +std::future Query::resolveArguments(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getArguments(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -206,7 +204,7 @@ service::FieldResult> Query::getFindDog(service::FieldParam throw std::runtime_error(R"ex(Query::getFindDog is not implemented)ex"); } -std::future Query::resolveFindDog(service::ResolverParams&& params) +std::future Query::resolveFindDog(service::ResolverParams&& params) { auto argComplex = service::ModifiedArgument::require("complex", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -221,7 +219,7 @@ service::FieldResult> Query::getBooleanList throw std::runtime_error(R"ex(Query::getBooleanList is not implemented)ex"); } -std::future Query::resolveBooleanList(service::ResolverParams&& params) +std::future Query::resolveBooleanList(service::ResolverParams&& params) { auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -231,21 +229,23 @@ std::future Query::resolveBooleanList(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Query::resolve_typename(service::ResolverParams&& params) +std::future Query::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Query)gql" }, std::move(params)); } -std::future Query::resolve_schema(service::ResolverParams&& params) +std::future Query::resolve_schema(service::ResolverParams&& params) { - return service::ModifiedResult::convert(std::static_pointer_cast(_schema), std::move(params)); + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared(_schema)), std::move(params)); } -std::future Query::resolve_type(service::ResolverParams&& params) +std::future Query::resolve_type(service::ResolverParams&& params) { auto argName = service::ModifiedArgument::require("name", params.arguments); + const auto& baseType = _schema->LookupType(argName); + std::shared_ptr result { baseType ? std::make_shared(baseType) : nullptr }; - return service::ModifiedResult::convert(_schema->LookupType(argName), std::move(params)); + return service::ModifiedResult::convert(result, std::move(params)); } Dog::Dog() @@ -271,7 +271,7 @@ service::FieldResult Dog::getName(service::FieldParams&&) throw std::runtime_error(R"ex(Dog::getName is not implemented)ex"); } -std::future Dog::resolveName(service::ResolverParams&& params) +std::future Dog::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -285,7 +285,7 @@ service::FieldResult> Dog::getNickname(servi throw std::runtime_error(R"ex(Dog::getNickname is not implemented)ex"); } -std::future Dog::resolveNickname(service::ResolverParams&& params) +std::future Dog::resolveNickname(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNickname(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -299,7 +299,7 @@ service::FieldResult> Dog::getBarkVolume(servic throw std::runtime_error(R"ex(Dog::getBarkVolume is not implemented)ex"); } -std::future Dog::resolveBarkVolume(service::ResolverParams&& params) +std::future Dog::resolveBarkVolume(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getBarkVolume(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -313,7 +313,7 @@ service::FieldResult Dog::getDoesKnowCommand(service::Fie throw std::runtime_error(R"ex(Dog::getDoesKnowCommand is not implemented)ex"); } -std::future Dog::resolveDoesKnowCommand(service::ResolverParams&& params) +std::future Dog::resolveDoesKnowCommand(service::ResolverParams&& params) { auto argDogCommand = service::ModifiedArgument::require("dogCommand", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -328,7 +328,7 @@ service::FieldResult Dog::getIsHousetrained(service::Fiel throw std::runtime_error(R"ex(Dog::getIsHousetrained is not implemented)ex"); } -std::future Dog::resolveIsHousetrained(service::ResolverParams&& params) +std::future Dog::resolveIsHousetrained(service::ResolverParams&& params) { auto argAtOtherHomes = service::ModifiedArgument::require("atOtherHomes", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -343,7 +343,7 @@ service::FieldResult> Dog::getOwner(service::FieldParams& throw std::runtime_error(R"ex(Dog::getOwner is not implemented)ex"); } -std::future Dog::resolveOwner(service::ResolverParams&& params) +std::future Dog::resolveOwner(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getOwner(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -352,7 +352,7 @@ std::future Dog::resolveOwner(service::ResolverParams&& params) return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Dog::resolve_typename(service::ResolverParams&& params) +std::future Dog::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Dog)gql" }, std::move(params)); } @@ -375,7 +375,7 @@ service::FieldResult Alien::getName(service::FieldParams&& throw std::runtime_error(R"ex(Alien::getName is not implemented)ex"); } -std::future Alien::resolveName(service::ResolverParams&& params) +std::future Alien::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -389,7 +389,7 @@ service::FieldResult> Alien::getHomePlanet(s throw std::runtime_error(R"ex(Alien::getHomePlanet is not implemented)ex"); } -std::future Alien::resolveHomePlanet(service::ResolverParams&& params) +std::future Alien::resolveHomePlanet(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getHomePlanet(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -398,7 +398,7 @@ std::future Alien::resolveHomePlanet(service::ResolverParams&& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Alien::resolve_typename(service::ResolverParams&& params) +std::future Alien::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Alien)gql" }, std::move(params)); } @@ -422,7 +422,7 @@ service::FieldResult Human::getName(service::FieldParams&& throw std::runtime_error(R"ex(Human::getName is not implemented)ex"); } -std::future Human::resolveName(service::ResolverParams&& params) +std::future Human::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -436,7 +436,7 @@ service::FieldResult>> Human::getPe throw std::runtime_error(R"ex(Human::getPets is not implemented)ex"); } -std::future Human::resolvePets(service::ResolverParams&& params) +std::future Human::resolvePets(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getPets(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -445,7 +445,7 @@ std::future Human::resolvePets(service::ResolverParams&& params return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Human::resolve_typename(service::ResolverParams&& params) +std::future Human::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Human)gql" }, std::move(params)); } @@ -470,7 +470,7 @@ service::FieldResult Cat::getName(service::FieldParams&&) throw std::runtime_error(R"ex(Cat::getName is not implemented)ex"); } -std::future Cat::resolveName(service::ResolverParams&& params) +std::future Cat::resolveName(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getName(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -484,7 +484,7 @@ service::FieldResult> Cat::getNickname(servi throw std::runtime_error(R"ex(Cat::getNickname is not implemented)ex"); } -std::future Cat::resolveNickname(service::ResolverParams&& params) +std::future Cat::resolveNickname(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNickname(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -498,7 +498,7 @@ service::FieldResult Cat::getDoesKnowCommand(service::Fie throw std::runtime_error(R"ex(Cat::getDoesKnowCommand is not implemented)ex"); } -std::future Cat::resolveDoesKnowCommand(service::ResolverParams&& params) +std::future Cat::resolveDoesKnowCommand(service::ResolverParams&& params) { auto argCatCommand = service::ModifiedArgument::require("catCommand", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -513,7 +513,7 @@ service::FieldResult> Cat::getMeowVolume(servic throw std::runtime_error(R"ex(Cat::getMeowVolume is not implemented)ex"); } -std::future Cat::resolveMeowVolume(service::ResolverParams&& params) +std::future Cat::resolveMeowVolume(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getMeowVolume(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -522,7 +522,7 @@ std::future Cat::resolveMeowVolume(service::ResolverParams&& pa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Cat::resolve_typename(service::ResolverParams&& params) +std::future Cat::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Cat)gql" }, std::move(params)); } @@ -542,7 +542,7 @@ service::FieldResult> Mutation::applyMutateDog( throw std::runtime_error(R"ex(Mutation::applyMutateDog is not implemented)ex"); } -std::future Mutation::resolveMutateDog(service::ResolverParams&& params) +std::future Mutation::resolveMutateDog(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = applyMutateDog(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -551,7 +551,7 @@ std::future Mutation::resolveMutateDog(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Mutation::resolve_typename(service::ResolverParams&& params) +std::future Mutation::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Mutation)gql" }, std::move(params)); } @@ -571,7 +571,7 @@ service::FieldResult MutateDogResult::getId(service::FieldPara throw std::runtime_error(R"ex(MutateDogResult::getId is not implemented)ex"); } -std::future MutateDogResult::resolveId(service::ResolverParams&& params) +std::future MutateDogResult::resolveId(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getId(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -580,7 +580,7 @@ std::future MutateDogResult::resolveId(service::ResolverParams& return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future MutateDogResult::resolve_typename(service::ResolverParams&& params) +std::future MutateDogResult::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(MutateDogResult)gql" }, std::move(params)); } @@ -601,7 +601,7 @@ service::FieldResult> Subscription::getNewMessage(servi throw std::runtime_error(R"ex(Subscription::getNewMessage is not implemented)ex"); } -std::future Subscription::resolveNewMessage(service::ResolverParams&& params) +std::future Subscription::resolveNewMessage(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getNewMessage(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -615,7 +615,7 @@ service::FieldResult Subscription::getDisallowedSecondRoo throw std::runtime_error(R"ex(Subscription::getDisallowedSecondRootField is not implemented)ex"); } -std::future Subscription::resolveDisallowedSecondRootField(service::ResolverParams&& params) +std::future Subscription::resolveDisallowedSecondRootField(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getDisallowedSecondRootField(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -624,7 +624,7 @@ std::future Subscription::resolveDisallowedSecondRootField(serv return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Subscription::resolve_typename(service::ResolverParams&& params) +std::future Subscription::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Subscription)gql" }, std::move(params)); } @@ -645,7 +645,7 @@ service::FieldResult> Message::getBody(servi throw std::runtime_error(R"ex(Message::getBody is not implemented)ex"); } -std::future Message::resolveBody(service::ResolverParams&& params) +std::future Message::resolveBody(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getBody(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -659,7 +659,7 @@ service::FieldResult Message::getSender(service::FieldParams&& throw std::runtime_error(R"ex(Message::getSender is not implemented)ex"); } -std::future Message::resolveSender(service::ResolverParams&& params) +std::future Message::resolveSender(service::ResolverParams&& params) { std::unique_lock resolverLock(_resolverMutex); auto result = getSender(service::FieldParams(params, std::move(params.fieldDirectives))); @@ -668,7 +668,7 @@ std::future Message::resolveSender(service::ResolverParams&& pa return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Message::resolve_typename(service::ResolverParams&& params) +std::future Message::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Message)gql" }, std::move(params)); } @@ -695,7 +695,7 @@ service::FieldResult Arguments::getMultipleReqs(service::Fiel throw std::runtime_error(R"ex(Arguments::getMultipleReqs is not implemented)ex"); } -std::future Arguments::resolveMultipleReqs(service::ResolverParams&& params) +std::future Arguments::resolveMultipleReqs(service::ResolverParams&& params) { auto argX = service::ModifiedArgument::require("x", params.arguments); auto argY = service::ModifiedArgument::require("y", params.arguments); @@ -711,7 +711,7 @@ service::FieldResult> Arguments::getBoolean throw std::runtime_error(R"ex(Arguments::getBooleanArgField is not implemented)ex"); } -std::future Arguments::resolveBooleanArgField(service::ResolverParams&& params) +std::future Arguments::resolveBooleanArgField(service::ResolverParams&& params) { auto argBooleanArg = service::ModifiedArgument::require("booleanArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -726,7 +726,7 @@ service::FieldResult> Arguments::getFloatArgF throw std::runtime_error(R"ex(Arguments::getFloatArgField is not implemented)ex"); } -std::future Arguments::resolveFloatArgField(service::ResolverParams&& params) +std::future Arguments::resolveFloatArgField(service::ResolverParams&& params) { auto argFloatArg = service::ModifiedArgument::require("floatArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -741,7 +741,7 @@ service::FieldResult> Arguments::getIntArgField throw std::runtime_error(R"ex(Arguments::getIntArgField is not implemented)ex"); } -std::future Arguments::resolveIntArgField(service::ResolverParams&& params) +std::future Arguments::resolveIntArgField(service::ResolverParams&& params) { auto argIntArg = service::ModifiedArgument::require("intArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -756,7 +756,7 @@ service::FieldResult Arguments::getNonNullBooleanArgField throw std::runtime_error(R"ex(Arguments::getNonNullBooleanArgField is not implemented)ex"); } -std::future Arguments::resolveNonNullBooleanArgField(service::ResolverParams&& params) +std::future Arguments::resolveNonNullBooleanArgField(service::ResolverParams&& params) { auto argNonNullBooleanArg = service::ModifiedArgument::require("nonNullBooleanArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -771,7 +771,7 @@ service::FieldResult>> Argument throw std::runtime_error(R"ex(Arguments::getNonNullBooleanListField is not implemented)ex"); } -std::future Arguments::resolveNonNullBooleanListField(service::ResolverParams&& params) +std::future Arguments::resolveNonNullBooleanListField(service::ResolverParams&& params) { auto argNonNullBooleanListArg = service::ModifiedArgument::require("nonNullBooleanListArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -786,7 +786,7 @@ service::FieldResult Arguments::resolveBooleanListArgField(service::ResolverParams&& params) +std::future Arguments::resolveBooleanListArgField(service::ResolverParams&& params) { auto argBooleanListArg = service::ModifiedArgument::require("booleanListArg", params.arguments); std::unique_lock resolverLock(_resolverMutex); @@ -801,7 +801,7 @@ service::FieldResult Arguments::getOptionalNonNullBoolean throw std::runtime_error(R"ex(Arguments::getOptionalNonNullBooleanArgField is not implemented)ex"); } -std::future Arguments::resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params) +std::future Arguments::resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params) { const auto defaultArguments = []() { @@ -825,7 +825,7 @@ std::future Arguments::resolveOptionalNonNullBooleanArgField(se return service::ModifiedResult::convert(std::move(result), std::move(params)); } -std::future Arguments::resolve_typename(service::ResolverParams&& params) +std::future Arguments::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql(Arguments)gql" }, std::move(params)); } @@ -837,179 +837,179 @@ Operations::Operations(std::shared_ptr query, std::shared_ptr& schema) -{ - auto typeDogCommand = std::make_shared("DogCommand", R"md()md"); - schema->AddType("DogCommand", typeDogCommand); - auto typeCatCommand = std::make_shared("CatCommand", R"md()md"); - schema->AddType("CatCommand", typeCatCommand); - auto typeComplexInput = std::make_shared("ComplexInput", R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"); - schema->AddType("ComplexInput", typeComplexInput); - auto typeCatOrDog = std::make_shared("CatOrDog", R"md()md"); - schema->AddType("CatOrDog", typeCatOrDog); - auto typeDogOrHuman = std::make_shared("DogOrHuman", R"md()md"); - schema->AddType("DogOrHuman", typeDogOrHuman); - auto typeHumanOrAlien = std::make_shared("HumanOrAlien", R"md()md"); - schema->AddType("HumanOrAlien", typeHumanOrAlien); - auto typeSentient = std::make_shared("Sentient", R"md()md"); - schema->AddType("Sentient", typeSentient); - auto typePet = std::make_shared("Pet", R"md()md"); - schema->AddType("Pet", typePet); - auto typeQuery = std::make_shared("Query", R"md(GraphQL validation [sample](http://spec.graphql.org/June2018/#example-26a9d))md"); - schema->AddType("Query", typeQuery); - auto typeDog = std::make_shared("Dog", R"md()md"); - schema->AddType("Dog", typeDog); - auto typeAlien = std::make_shared("Alien", R"md()md"); - schema->AddType("Alien", typeAlien); - auto typeHuman = std::make_shared("Human", R"md()md"); - schema->AddType("Human", typeHuman); - auto typeCat = std::make_shared("Cat", R"md()md"); - schema->AddType("Cat", typeCat); - auto typeMutation = std::make_shared("Mutation", R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); - schema->AddType("Mutation", typeMutation); - auto typeMutateDogResult = std::make_shared("MutateDogResult", R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); - schema->AddType("MutateDogResult", typeMutateDogResult); - auto typeSubscription = std::make_shared("Subscription", R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); - schema->AddType("Subscription", typeSubscription); - auto typeMessage = std::make_shared("Message", R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); - schema->AddType("Message", typeMessage); - auto typeArguments = std::make_shared("Arguments", R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md"); - schema->AddType("Arguments", typeArguments); +void AddTypesToSchema(const std::shared_ptr& schema) +{ + auto typeDogCommand = schema::EnumType::Make(R"gql(DogCommand)gql"sv, R"md()md"sv); + schema->AddType(R"gql(DogCommand)gql"sv, typeDogCommand); + auto typeCatCommand = schema::EnumType::Make(R"gql(CatCommand)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CatCommand)gql"sv, typeCatCommand); + auto typeComplexInput = schema::InputObjectType::Make(R"gql(ComplexInput)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv); + schema->AddType(R"gql(ComplexInput)gql"sv, typeComplexInput); + auto typeCatOrDog = schema::UnionType::Make(R"gql(CatOrDog)gql"sv, R"md()md"sv); + schema->AddType(R"gql(CatOrDog)gql"sv, typeCatOrDog); + auto typeDogOrHuman = schema::UnionType::Make(R"gql(DogOrHuman)gql"sv, R"md()md"sv); + schema->AddType(R"gql(DogOrHuman)gql"sv, typeDogOrHuman); + auto typeHumanOrAlien = schema::UnionType::Make(R"gql(HumanOrAlien)gql"sv, R"md()md"sv); + schema->AddType(R"gql(HumanOrAlien)gql"sv, typeHumanOrAlien); + auto typeSentient = schema::InterfaceType::Make(R"gql(Sentient)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Sentient)gql"sv, typeSentient); + auto typePet = schema::InterfaceType::Make(R"gql(Pet)gql"sv, R"md()md"sv); + schema->AddType(R"gql(Pet)gql"sv, typePet); + auto typeQuery = schema::ObjectType::Make(R"gql(Query)gql"sv, R"md(GraphQL validation [sample](http://spec.graphql.org/June2018/#example-26a9d))md"); + schema->AddType(R"gql(Query)gql"sv, typeQuery); + auto typeDog = schema::ObjectType::Make(R"gql(Dog)gql"sv, R"md()md"); + schema->AddType(R"gql(Dog)gql"sv, typeDog); + auto typeAlien = schema::ObjectType::Make(R"gql(Alien)gql"sv, R"md()md"); + schema->AddType(R"gql(Alien)gql"sv, typeAlien); + auto typeHuman = schema::ObjectType::Make(R"gql(Human)gql"sv, R"md()md"); + schema->AddType(R"gql(Human)gql"sv, typeHuman); + auto typeCat = schema::ObjectType::Make(R"gql(Cat)gql"sv, R"md()md"); + schema->AddType(R"gql(Cat)gql"sv, typeCat); + auto typeMutation = schema::ObjectType::Make(R"gql(Mutation)gql"sv, R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); + schema->AddType(R"gql(Mutation)gql"sv, typeMutation); + auto typeMutateDogResult = schema::ObjectType::Make(R"gql(MutateDogResult)gql"sv, R"md(Support for [Counter Example 94](http://spec.graphql.org/June2018/#example-77c2e))md"); + schema->AddType(R"gql(MutateDogResult)gql"sv, typeMutateDogResult); + auto typeSubscription = schema::ObjectType::Make(R"gql(Subscription)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); + schema->AddType(R"gql(Subscription)gql"sv, typeSubscription); + auto typeMessage = schema::ObjectType::Make(R"gql(Message)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"); + schema->AddType(R"gql(Message)gql"sv, typeMessage); + auto typeArguments = schema::ObjectType::Make(R"gql(Arguments)gql"sv, R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md"); + schema->AddType(R"gql(Arguments)gql"sv, typeArguments); typeDogCommand->AddEnumValues({ - { std::string{ service::s_namesDogCommand[static_cast(validation::DogCommand::SIT)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDogCommand[static_cast(validation::DogCommand::DOWN)] }, R"md()md", std::nullopt }, - { std::string{ service::s_namesDogCommand[static_cast(validation::DogCommand::HEEL)] }, R"md()md", std::nullopt } + { service::s_namesDogCommand[static_cast(validation::DogCommand::SIT)], R"md()md"sv, std::nullopt }, + { service::s_namesDogCommand[static_cast(validation::DogCommand::DOWN)], R"md()md"sv, std::nullopt }, + { service::s_namesDogCommand[static_cast(validation::DogCommand::HEEL)], R"md()md"sv, std::nullopt } }); typeCatCommand->AddEnumValues({ - { std::string{ service::s_namesCatCommand[static_cast(validation::CatCommand::JUMP)] }, R"md()md", std::nullopt } + { service::s_namesCatCommand[static_cast(validation::CatCommand::JUMP)], R"md()md"sv, std::nullopt } }); typeComplexInput->AddInputValues({ - std::make_shared("name", R"md()md", schema->LookupType("String"), R"gql()gql"), - std::make_shared("owner", R"md()md", schema->LookupType("String"), R"gql()gql") + schema::InputValue::Make(R"gql(name)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv), + schema::InputValue::Make(R"gql(owner)gql"sv, R"md()md"sv, schema->LookupType("String"), R"gql()gql"sv) }); typeCatOrDog->AddPossibleTypes({ - schema->LookupType("Cat"), - schema->LookupType("Dog") + schema->LookupType(R"gql(Cat)gql"sv), + schema->LookupType(R"gql(Dog)gql"sv) }); typeDogOrHuman->AddPossibleTypes({ - schema->LookupType("Dog"), - schema->LookupType("Human") + schema->LookupType(R"gql(Dog)gql"sv), + schema->LookupType(R"gql(Human)gql"sv) }); typeHumanOrAlien->AddPossibleTypes({ - schema->LookupType("Human"), - schema->LookupType("Alien") + schema->LookupType(R"gql(Human)gql"sv), + schema->LookupType(R"gql(Alien)gql"sv) }); typeSentient->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) }); typePet->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))) }); typeQuery->AddFields({ - std::make_shared("dog", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Dog")), - std::make_shared("human", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector>(), schema->LookupType("Human")), - std::make_shared("pet", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector>(), schema->LookupType("Pet")), - std::make_shared("catOrDog", R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md", std::nullopt, std::vector>(), schema->LookupType("CatOrDog")), - std::make_shared("arguments", R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md", std::nullopt, std::vector>(), schema->LookupType("Arguments")), - std::make_shared("findDog", R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md", std::nullopt, std::vector>({ - std::make_shared("complex", R"md()md", schema->LookupType("ComplexInput"), R"gql()gql") - }), schema->LookupType("Dog")), - std::make_shared("booleanList", R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md", std::nullopt, std::vector>({ - std::make_shared("booleanListArg", R"md()md", schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql") - }), schema->LookupType("Boolean")) + schema::Field::Make(R"gql(dog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Dog")), + schema::Field::Make(R"gql(human)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("Human")), + schema::Field::Make(R"gql(pet)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("Pet")), + schema::Field::Make(R"gql(catOrDog)gql"sv, R"md(Support for [Counter Example 116](http://spec.graphql.org/June2018/#example-77c2e))md"sv, std::nullopt, schema->LookupType("CatOrDog")), + schema::Field::Make(R"gql(arguments)gql"sv, R"md(Support for [Example 120](http://spec.graphql.org/June2018/#example-1891c))md"sv, std::nullopt, schema->LookupType("Arguments")), + schema::Field::Make(R"gql(findDog)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv, std::nullopt, schema->LookupType("Dog"), { + schema::InputValue::Make(R"gql(complex)gql"sv, R"md()md"sv, schema->LookupType("ComplexInput"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanList)gql"sv, R"md([Example 155](http://spec.graphql.org/June2018/#example-f3185))md"sv, std::nullopt, schema->LookupType("Boolean"), { + schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql"sv) + }) }); typeDog->AddInterfaces({ typePet }); typeDog->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("nickname", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("barkVolume", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Int")), - std::make_shared("doesKnowCommand", R"md()md", std::nullopt, std::vector>({ - std::make_shared("dogCommand", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("DogCommand")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("isHousetrained", R"md()md", std::nullopt, std::vector>({ - std::make_shared("atOtherHomes", R"md()md", schema->LookupType("Boolean"), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("owner", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Human")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(barkVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int")), + schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(dogCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("DogCommand")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(isHousetrained)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(atOtherHomes)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(owner)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Human")) }); typeAlien->AddInterfaces({ typeSentient }); typeAlien->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("homePlanet", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(homePlanet)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")) }); typeHuman->AddInterfaces({ typeSentient }); typeHuman->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("pets", R"md(Support for [Counter Example 136](http://spec.graphql.org/June2018/#example-6bbad))md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Pet"))))) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(pets)gql"sv, R"md(Support for [Counter Example 136](http://spec.graphql.org/June2018/#example-6bbad))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Pet"))))) }); typeCat->AddInterfaces({ typePet }); typeCat->AddFields({ - std::make_shared("name", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), - std::make_shared("nickname", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("doesKnowCommand", R"md()md", std::nullopt, std::vector>({ - std::make_shared("catCommand", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CatCommand")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("meowVolume", R"md()md", std::nullopt, std::vector>(), schema->LookupType("Int")) + schema::Field::Make(R"gql(name)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("String"))), + schema::Field::Make(R"gql(nickname)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(doesKnowCommand)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(catCommand)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("CatCommand")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(meowVolume)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int")) }); typeMutation->AddFields({ - std::make_shared("mutateDog", R"md()md", std::nullopt, std::vector>(), schema->LookupType("MutateDogResult")) + schema::Field::Make(R"gql(mutateDog)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("MutateDogResult")) }); typeMutateDogResult->AddFields({ - std::make_shared("id", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + schema::Field::Make(R"gql(id)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) }); typeSubscription->AddFields({ - std::make_shared("newMessage", R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Message"))), - std::make_shared("disallowedSecondRootField", R"md(Support for [Counter Example 99](http://spec.graphql.org/June2018/#example-3997d) - [Counter Example 100](http://spec.graphql.org/June2018/#example-18466))md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(newMessage)gql"sv, R"md(Support for [Example 97](http://spec.graphql.org/June2018/#example-5bbc3) - [Counter Example 101](http://spec.graphql.org/June2018/#example-2353b))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Message"))), + schema::Field::Make(R"gql(disallowedSecondRootField)gql"sv, R"md(Support for [Counter Example 99](http://spec.graphql.org/June2018/#example-3997d) - [Counter Example 100](http://spec.graphql.org/June2018/#example-18466))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) }); typeMessage->AddFields({ - std::make_shared("body", R"md()md", std::nullopt, std::vector>(), schema->LookupType("String")), - std::make_shared("sender", R"md()md", std::nullopt, std::vector>(), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) + schema::Field::Make(R"gql(body)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("String")), + schema::Field::Make(R"gql(sender)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("ID"))) }); typeArguments->AddFields({ - std::make_shared("multipleReqs", R"md(Support for [Example 121](http://spec.graphql.org/June2018/#example-18fab))md", std::nullopt, std::vector>({ - std::make_shared("x", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"), - std::make_shared("y", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int"))), - std::make_shared("booleanArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("booleanArg", R"md()md", schema->LookupType("Boolean"), R"gql()gql") - }), schema->LookupType("Boolean")), - std::make_shared("floatArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("floatArg", R"md()md", schema->LookupType("Float"), R"gql()gql") - }), schema->LookupType("Float")), - std::make_shared("intArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("intArg", R"md()md", schema->LookupType("Int"), R"gql()gql") - }), schema->LookupType("Int")), - std::make_shared("nonNullBooleanArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("nonNullBooleanArg", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), - std::make_shared("nonNullBooleanListField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("nonNullBooleanListArg", R"md()md", schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")))), - std::make_shared("booleanListArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("booleanListArg", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean"))), R"gql()gql") - }), schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean"))), - std::make_shared("optionalNonNullBooleanArgField", R"md()md", std::nullopt, std::vector>({ - std::make_shared("optionalBooleanArg", R"md()md", schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql(false)gql") - }), schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))) + schema::Field::Make(R"gql(multipleReqs)gql"sv, R"md(Support for [Example 121](http://spec.graphql.org/June2018/#example-18fab))md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), { + schema::InputValue::Make(R"gql(x)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"sv), + schema::InputValue::Make(R"gql(y)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Int")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Boolean"), { + schema::InputValue::Make(R"gql(booleanArg)gql"sv, R"md()md"sv, schema->LookupType("Boolean"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(floatArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Float"), { + schema::InputValue::Make(R"gql(floatArg)gql"sv, R"md()md"sv, schema->LookupType("Float"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(intArgField)gql"sv, R"md()md"sv, std::nullopt, schema->LookupType("Int"), { + schema::InputValue::Make(R"gql(intArg)gql"sv, R"md()md"sv, schema->LookupType("Int"), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(nonNullBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(nonNullBooleanListField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), { + schema::InputValue::Make(R"gql(nonNullBooleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::LIST, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean"))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(booleanListArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(booleanListArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->WrapType(introspection::TypeKind::LIST, schema->LookupType("Boolean"))), R"gql()gql"sv) + }), + schema::Field::Make(R"gql(optionalNonNullBooleanArgField)gql"sv, R"md()md"sv, std::nullopt, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), { + schema::InputValue::Make(R"gql(optionalBooleanArg)gql"sv, R"md()md"sv, schema->WrapType(introspection::TypeKind::NON_NULL, schema->LookupType("Boolean")), R"gql(false)gql"sv) + }) }); schema->AddQueryType(typeQuery); @@ -1017,5 +1017,21 @@ void AddTypesToSchema(const std::shared_ptr& schema) schema->AddSubscriptionType(typeSubscription); } +std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared(false); + introspection::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + } /* namespace validation */ } /* namespace graphql */ diff --git a/samples/validation/ValidationSchema.h b/samples/validation/ValidationSchema.h index 3f4e710b..906f3f0f 100644 --- a/samples/validation/ValidationSchema.h +++ b/samples/validation/ValidationSchema.h @@ -6,6 +6,7 @@ #ifndef VALIDATIONSCHEMA_H #define VALIDATIONSCHEMA_H +#include "graphqlservice/GraphQLSchema.h" #include "graphqlservice/GraphQLService.h" #include @@ -13,12 +14,6 @@ #include namespace graphql { -namespace introspection { - -class Schema; - -} /* namespace introspection */ - namespace validation { enum class DogCommand @@ -85,19 +80,19 @@ class Query virtual service::FieldResult> getBooleanList(service::FieldParams&& params, std::optional>&& booleanListArgArg) const; private: - std::future resolveDog(service::ResolverParams&& params); - std::future resolveHuman(service::ResolverParams&& params); - std::future resolvePet(service::ResolverParams&& params); - std::future resolveCatOrDog(service::ResolverParams&& params); - std::future resolveArguments(service::ResolverParams&& params); - std::future resolveFindDog(service::ResolverParams&& params); - std::future resolveBooleanList(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); - std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); - - std::shared_ptr _schema; + std::future resolveDog(service::ResolverParams&& params); + std::future resolveHuman(service::ResolverParams&& params); + std::future resolvePet(service::ResolverParams&& params); + std::future resolveCatOrDog(service::ResolverParams&& params); + std::future resolveArguments(service::ResolverParams&& params); + std::future resolveFindDog(service::ResolverParams&& params); + std::future resolveBooleanList(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_schema(service::ResolverParams&& params); + std::future resolve_type(service::ResolverParams&& params); + + std::shared_ptr _schema; }; class Dog @@ -116,14 +111,14 @@ class Dog virtual service::FieldResult> getOwner(service::FieldParams&& params) const; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveNickname(service::ResolverParams&& params); - std::future resolveBarkVolume(service::ResolverParams&& params); - std::future resolveDoesKnowCommand(service::ResolverParams&& params); - std::future resolveIsHousetrained(service::ResolverParams&& params); - std::future resolveOwner(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveNickname(service::ResolverParams&& params); + std::future resolveBarkVolume(service::ResolverParams&& params); + std::future resolveDoesKnowCommand(service::ResolverParams&& params); + std::future resolveIsHousetrained(service::ResolverParams&& params); + std::future resolveOwner(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); }; class Alien @@ -138,10 +133,10 @@ class Alien virtual service::FieldResult> getHomePlanet(service::FieldParams&& params) const; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveHomePlanet(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveHomePlanet(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Human @@ -156,10 +151,10 @@ class Human virtual service::FieldResult>> getPets(service::FieldParams&& params) const; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolvePets(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolvePets(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Cat @@ -176,12 +171,12 @@ class Cat virtual service::FieldResult> getMeowVolume(service::FieldParams&& params) const; private: - std::future resolveName(service::ResolverParams&& params); - std::future resolveNickname(service::ResolverParams&& params); - std::future resolveDoesKnowCommand(service::ResolverParams&& params); - std::future resolveMeowVolume(service::ResolverParams&& params); + std::future resolveName(service::ResolverParams&& params); + std::future resolveNickname(service::ResolverParams&& params); + std::future resolveDoesKnowCommand(service::ResolverParams&& params); + std::future resolveMeowVolume(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Mutation @@ -194,9 +189,9 @@ class Mutation virtual service::FieldResult> applyMutateDog(service::FieldParams&& params) const; private: - std::future resolveMutateDog(service::ResolverParams&& params); + std::future resolveMutateDog(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class MutateDogResult @@ -209,9 +204,9 @@ class MutateDogResult virtual service::FieldResult getId(service::FieldParams&& params) const; private: - std::future resolveId(service::ResolverParams&& params); + std::future resolveId(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Subscription @@ -225,10 +220,10 @@ class Subscription virtual service::FieldResult getDisallowedSecondRootField(service::FieldParams&& params) const; private: - std::future resolveNewMessage(service::ResolverParams&& params); - std::future resolveDisallowedSecondRootField(service::ResolverParams&& params); + std::future resolveNewMessage(service::ResolverParams&& params); + std::future resolveDisallowedSecondRootField(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Message @@ -242,10 +237,10 @@ class Message virtual service::FieldResult getSender(service::FieldParams&& params) const; private: - std::future resolveBody(service::ResolverParams&& params); - std::future resolveSender(service::ResolverParams&& params); + std::future resolveBody(service::ResolverParams&& params); + std::future resolveSender(service::ResolverParams&& params); - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); }; class Arguments @@ -265,16 +260,16 @@ class Arguments virtual service::FieldResult getOptionalNonNullBooleanArgField(service::FieldParams&& params, response::BooleanType&& optionalBooleanArgArg) const; private: - std::future resolveMultipleReqs(service::ResolverParams&& params); - std::future resolveBooleanArgField(service::ResolverParams&& params); - std::future resolveFloatArgField(service::ResolverParams&& params); - std::future resolveIntArgField(service::ResolverParams&& params); - std::future resolveNonNullBooleanArgField(service::ResolverParams&& params); - std::future resolveNonNullBooleanListField(service::ResolverParams&& params); - std::future resolveBooleanListArgField(service::ResolverParams&& params); - std::future resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params); - - std::future resolve_typename(service::ResolverParams&& params); + std::future resolveMultipleReqs(service::ResolverParams&& params); + std::future resolveBooleanArgField(service::ResolverParams&& params); + std::future resolveFloatArgField(service::ResolverParams&& params); + std::future resolveIntArgField(service::ResolverParams&& params); + std::future resolveNonNullBooleanArgField(service::ResolverParams&& params); + std::future resolveNonNullBooleanListField(service::ResolverParams&& params); + std::future resolveBooleanListArgField(service::ResolverParams&& params); + std::future resolveOptionalNonNullBooleanArgField(service::ResolverParams&& params); + + std::future resolve_typename(service::ResolverParams&& params); }; } /* namespace object */ @@ -291,7 +286,7 @@ class Operations std::shared_ptr _subscription; }; -void AddTypesToSchema(const std::shared_ptr& schema); +std::shared_ptr GetSchema(); } /* namespace validation */ } /* namespace graphql */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 23617111..a3e14f61 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -113,8 +113,8 @@ if(GRAPHQL_UPDATE_SAMPLES) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../IntrospectionSchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/IntrospectionSchema.h - COMMAND ${CMAKE_COMMAND} -E make_directory include/graphqlservice + ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h + COMMAND ${CMAKE_COMMAND} -E make_directory include/graphqlservice/introspection COMMAND schemagen --introspection DEPENDS schemagen WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.. @@ -126,11 +126,11 @@ if(GRAPHQL_UPDATE_SAMPLES) OUTPUT updated_introspection COMMAND ${CMAKE_COMMAND} -E remove -f ${OLD_INTROSPECTION_FILES} COMMAND ${CMAKE_COMMAND} -E copy ../IntrospectionSchema.cpp ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/ - COMMAND ${CMAKE_COMMAND} -E copy ../include/graphqlservice/IntrospectionSchema.h ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/ + COMMAND ${CMAKE_COMMAND} -E copy ../include/graphqlservice/introspection/IntrospectionSchema.h ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/ COMMAND ${CMAKE_COMMAND} -E touch updated_introspection DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../IntrospectionSchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/IntrospectionSchema.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h COMMENT "Updating introspection files") add_custom_target(update_introspection ALL @@ -139,32 +139,50 @@ else() add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../IntrospectionSchema.cpp - ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/IntrospectionSchema.h - COMMAND ${CMAKE_COMMAND} -E make_directory include/graphqlservice + ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h + COMMAND ${CMAKE_COMMAND} -E make_directory include/graphqlservice/introspection COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/IntrospectionSchema.cpp . - COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/IntrospectionSchema.h include/graphqlservice + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/../samples/introspection/IntrospectionSchema.h include/graphqlservice/introspection WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/.. COMMENT "Copying IntrospectionSchema files") endif() +add_custom_target(copy_introspection + DEPENDS + ${CMAKE_CURRENT_BINARY_DIR}/../IntrospectionSchema.cpp + ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h) + +# graphqlservice_nointrospection +add_library(graphqlservice_nointrospection + GraphQLService.cpp + GraphQLSchema.cpp + Validation.cpp) +add_dependencies(graphqlservice_nointrospection copy_introspection) +add_library(cppgraphqlgen::graphqlservice_nointrospection ALIAS graphqlservice_nointrospection) +target_link_libraries(graphqlservice_nointrospection PUBLIC + graphqlpeg + graphqlresponse + Threads::Threads) +target_include_directories(graphqlservice_nointrospection PUBLIC + $) + +if(WIN32 AND BUILD_SHARED_LIBS) + target_compile_definitions(graphqlservice_nointrospection + PUBLIC GRAPHQL_DLLEXPORTS + PRIVATE IMPL_GRAPHQLSERVICE_DLL) +endif() + # graphqlservice add_library(graphqlservice - GraphQLService.cpp Introspection.cpp - Validation.cpp ${CMAKE_CURRENT_BINARY_DIR}/../IntrospectionSchema.cpp) add_library(cppgraphqlgen::graphqlservice ALIAS graphqlservice) -target_link_libraries(graphqlservice PUBLIC - graphqlpeg - Threads::Threads) -target_link_libraries(graphqlservice PUBLIC graphqlresponse) -target_include_directories(graphqlservice PUBLIC - $) +target_link_libraries(graphqlservice PUBLIC graphqlservice_nointrospection) if(WIN32 AND BUILD_SHARED_LIBS) target_compile_definitions(graphqlservice PUBLIC GRAPHQL_DLLEXPORTS - PRIVATE IMPL_GRAPHQLSERVICE_DLL) + PRIVATE IMPL_GRAPHQLINTROSPECTION_DLL) endif() # RapidJSON is the only option for JSON serialization used in this project, but if you want @@ -212,6 +230,7 @@ endif() install(TARGETS graphqlpeg graphqlresponse + graphqlservice_nointrospection graphqlservice EXPORT cppgraphqlgen-targets RUNTIME DESTINATION bin @@ -221,14 +240,19 @@ install(TARGETS install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLParse.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLResponse.h + ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLSchema.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLService.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLGrammar.h ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/GraphQLTree.h - ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/Introspection.h - ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/IntrospectionSchema.h CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice) +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../include/graphqlservice/introspection/Introspection.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/graphqlservice/introspection/IntrospectionSchema.h + CONFIGURATIONS ${GRAPHQL_INSTALL_CONFIGURATIONS} + DESTINATION ${GRAPHQL_INSTALL_INCLUDE_DIR}/graphqlservice/introspection) + install(EXPORT cppgraphqlgen-targets NAMESPACE cppgraphqlgen:: DESTINATION ${GRAPHQL_INSTALL_CMAKE_DIR}/${PROJECT_NAME}) diff --git a/src/GraphQLResponse.cpp b/src/GraphQLResponse.cpp index 14748f84..69990f95 100644 --- a/src/GraphQLResponse.cpp +++ b/src/GraphQLResponse.cpp @@ -3,100 +3,313 @@ #include "graphqlservice/GraphQLResponse.h" +#include +#include +#include #include #include #include namespace graphql::response { -// Type::Map -struct MapData +bool Value::MapData::operator==(const MapData& rhs) const { - bool operator==(const MapData& rhs) const + return map == rhs.map; +} + +bool Value::StringData::operator==(const StringData& rhs) const +{ + return from_json == rhs.from_json && string == rhs.string; +} + +bool Value::NullData::operator==(const NullData&) const +{ + return true; +} + +bool Value::ScalarData::operator==(const ScalarData& rhs) const +{ + if (scalar && rhs.scalar) { - return map == rhs.map; + return *scalar == *rhs.scalar; } - MapType map; - std::unordered_map members; -}; + return !scalar && !rhs.scalar; +} -// Type::List -struct ListData +template <> +void Value::set(StringType&& value) { - bool operator==(const ListData& rhs) const + if (std::holds_alternative(_data)) { - return list == rhs.list; + std::get(_data) = std::move(value); } + else if (std::holds_alternative(_data)) + { + std::get(_data).string = std::move(value); + } + else + { + throw std::logic_error("Invalid call to Value::set for StringType"); + } +} - ListType list; -}; +template <> +void Value::set(BooleanType value) +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::set for BooleanType"); + } -// Type::String or Type::EnumValue -struct StringOrEnumData + _data = { value }; +} + +template <> +void Value::set(IntType value) { - bool operator==(const StringOrEnumData& rhs) const + if (std::holds_alternative(_data)) + { + // Coerce IntType to FloatType + _data = { static_cast(value) }; + return; + } + + if (!std::holds_alternative(_data)) { - return string == rhs.string && from_json == rhs.from_json; + throw std::logic_error("Invalid call to Value::set for IntType"); } - StringType string; - bool from_json = false; -}; + _data = { value }; +} -// Type::Scalar -struct ScalarData +template <> +void Value::set(FloatType value) { - bool operator==(const ScalarData& rhs) const + if (!std::holds_alternative(_data)) { - return scalar == rhs.scalar; + throw std::logic_error("Invalid call to Value::set for FloatType"); } - ScalarType scalar; -}; + _data = { value }; +} -struct TypedData - : std::variant, std::optional, std::optional, - std::optional, BooleanType, IntType, FloatType> +template <> +void Value::set(ScalarType&& value) { -}; + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::set for ScalarType"); + } + + _data = { ScalarData { std::make_unique(std::move(value)) } }; +} + +template <> +const MapType& Value::get() const +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for MapType"); + } + + return std::get(_data).map; +} + +template <> +const ListType& Value::get() const +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for ListType"); + } + + return std::get(_data); +} + +template <> +const StringType& Value::get() const +{ + if (std::holds_alternative(_data)) + { + return std::get(_data); + } + else if (std::holds_alternative(_data)) + { + return std::get(_data).string; + } + + throw std::logic_error("Invalid call to Value::get for StringType"); +} + +template <> +BooleanType Value::get() const +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for BooleanType"); + } + + return std::get(_data); +} + +template <> +IntType Value::get() const +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for IntType"); + } + + return std::get(_data); +} + +template <> +FloatType Value::get() const +{ + if (std::holds_alternative(_data)) + { + // Coerce IntType to FloatType + return static_cast(std::get(_data)); + } + + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for FloatType"); + } + + return std::get(_data); +} + +template <> +const ScalarType& Value::get() const +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::get for ScalarType"); + } + + const auto& scalar = std::get(_data).scalar; + + if (!scalar) + { + throw std::logic_error("Invalid call to Value::get for ScalarType"); + } + + return *scalar; +} + +template <> +MapType Value::release() +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::release for MapType"); + } + + auto& mapData = std::get(_data); + MapType result = std::move(mapData.map); + + mapData.members.clear(); + + return result; +} + +template <> +ListType Value::release() +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::release for ListType"); + } + + ListType result = std::move(std::get(_data)); + + return result; +} + +template <> +StringType Value::release() +{ + StringType result; + + if (std::holds_alternative(_data)) + { + result = std::move(std::get(_data)); + } + else if (std::holds_alternative(_data)) + { + auto& stringData = std::get(_data); + + result = std::move(stringData.string); + stringData.from_json = false; + } + else + { + throw std::logic_error("Invalid call to Value::release for StringType"); + } + + return result; +} + +template <> +ScalarType Value::release() +{ + if (!std::holds_alternative(_data)) + { + throw std::logic_error("Invalid call to Value::release for ScalarType"); + } + + auto scalar = std::move(std::get(_data).scalar); + + if (!scalar) + { + throw std::logic_error("Invalid call to Value::release for ScalarType"); + } + + ScalarType result = std::move(*scalar); + + return result; +} Value::Value(Type type /*= Type::Null*/) - : _type(type) { switch (type) { case Type::Map: - _data = std::make_unique(TypedData { std::make_optional() }); + _data = { MapData {} }; break; case Type::List: - _data = std::make_unique(TypedData { std::make_optional() }); + _data = { ListType {} }; break; case Type::String: - case Type::EnumValue: - _data = - std::make_unique(TypedData { std::make_optional() }); + _data = { StringData {} }; break; - case Type::Scalar: - _data = std::make_unique(TypedData { std::make_optional() }); + case Type::Null: + _data = { NullData {} }; break; case Type::Boolean: - _data = std::make_unique(TypedData { BooleanType { false } }); + _data = { BooleanType { false } }; break; case Type::Int: - _data = std::make_unique(TypedData { IntType { 0 } }); + _data = { IntType { 0 } }; break; case Type::Float: - _data = std::make_unique(TypedData { FloatType { 0.0 } }); + _data = { FloatType { 0.0 } }; break; - default: + case Type::EnumValue: + _data = { EnumData {} }; + break; + + case Type::Scalar: + _data = { ScalarData {} }; break; } } @@ -104,58 +317,121 @@ Value::Value(Type type /*= Type::Null*/) Value::~Value() { // The default destructor gets inlined and may use a different allocator to free Value's member - // variables than the graphqlservice module used to allocate them. So even though this could be - // omitted, declare it explicitly and define it in graphqlservice. + // variables than the graphqlresponse module used to allocate them. So even though this could be + // omitted, declare it explicitly and define it in graphqlresponse. } Value::Value(const char* value) - : _type(Type::String) - , _data(std::make_unique( - TypedData { StringOrEnumData { StringType { value }, false } })) + : _data(TypeData { StringData { StringType { value }, false } }) { } Value::Value(StringType&& value) - : _type(Type::String) - , _data(std::make_unique(TypedData { StringOrEnumData { std::move(value), false } })) + : _data(TypeData { StringData { std::move(value), false } }) { } Value::Value(BooleanType value) - : _type(Type::Boolean) - , _data(std::make_unique(TypedData { value })) + : _data(TypeData { value }) { } Value::Value(IntType value) - : _type(Type::Int) - , _data(std::make_unique(TypedData { value })) + : _data(TypeData { value }) { } Value::Value(FloatType value) - : _type(Type::Float) - , _data(std::make_unique(TypedData { value })) + : _data(TypeData { value }) { } Value::Value(Value&& other) noexcept - : _type(other.type()) - , _data(std::move(other._data)) + : _data(std::move(other._data)) { } Value::Value(const Value& other) - : _type(other.type()) - , _data(std::make_unique(other._data ? *other._data : TypedData {})) { + switch (other.type()) + { + case Type::Map: + { + MapData copy {}; + + copy.map.reserve(other.size()); + for (const auto& entry : other) + { + copy.map.push_back({ entry.first, Value { entry.second } }); + } + + std::map members; + + for (const auto& entry : copy.map) + { + members[entry.first] = members.size(); + } + + copy.members.reserve(members.size()); + std::transform(members.cbegin(), + members.cend(), + std::back_inserter(copy.members), + [©](const auto& entry) noexcept { + return entry.second; + }); + + _data = { std::move(copy) }; + break; + } + + case Type::List: + { + ListType copy {}; + + copy.reserve(other.size()); + for (size_t i = 0; i < other.size(); ++i) + { + copy.push_back(Value { other[i] }); + } + + _data = { std::move(copy) }; + break; + } + + case Type::String: + _data = { StringData { other.get(), other.maybe_enum() } }; + break; + + case Type::Null: + _data = { NullData {} }; + break; + + case Type::Boolean: + _data = { other.get() }; + break; + + case Type::Int: + _data = { other.get() }; + break; + + case Type::Float: + _data = { other.get() }; + break; + + case Type::EnumValue: + _data = { EnumData { other.get() } }; + break; + + case Type::Scalar: + _data = { ScalarData { std::make_unique(other.get()) } }; + break; + } } Value& Value::operator=(Value&& rhs) noexcept { if (&rhs != this) { - const_cast(_type) = rhs._type; _data = std::move(rhs._data); } @@ -164,12 +440,7 @@ Value& Value::operator=(Value&& rhs) noexcept bool Value::operator==(const Value& rhs) const noexcept { - if (rhs.type() != type()) - { - return false; - } - - return !_data || *_data == *rhs._data; + return _data == rhs._data; } bool Value::operator!=(const Value& rhs) const noexcept @@ -179,20 +450,58 @@ bool Value::operator!=(const Value& rhs) const noexcept Type Value::type() const noexcept { - return _data ? _type : Type::Null; + // As long as the order of the variant alternatives matches the Type enum, we can cast the index + // to the Type in one step. + static_assert( + std::is_same_v(Type::Map), TypeData>, + MapData>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::List), TypeData>, + ListType>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::String), TypeData>, + StringData>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::Boolean), TypeData>, + BooleanType>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::Int), TypeData>, + IntType>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::Float), TypeData>, + FloatType>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::EnumValue), TypeData>, + EnumData>, + "type mistmatch"); + static_assert( + std::is_same_v(Type::Scalar), TypeData>, + ScalarData>, + "type mistmatch"); + + return static_cast(_data.index()); } Value&& Value::from_json() noexcept { - std::get>(*_data)->from_json = true; + if (std::holds_alternative(_data)) + { + std::get(_data).from_json = true; + } return std::move(*this); } bool Value::maybe_enum() const noexcept { - return type() == Type::EnumValue - || (type() == Type::String && std::get>(*_data)->from_json); + return std::holds_alternative(_data) + || (std::holds_alternative(_data) && std::get(_data).from_json); } void Value::reserve(size_t count) @@ -201,18 +510,16 @@ void Value::reserve(size_t count) { case Type::Map: { - auto& mapData = std::get>(*_data); + auto& mapData = std::get(_data); - mapData->members.reserve(count); - mapData->map.reserve(count); + mapData.members.reserve(count); + mapData.map.reserve(count); break; } case Type::List: { - auto& listData = std::get>(*_data); - - listData->list.reserve(count); + std::get(_data).reserve(count); break; } @@ -227,16 +534,12 @@ size_t Value::size() const { case Type::Map: { - const auto& mapData = std::get>(*_data); - - return mapData->map.size(); + return std::get(_data).map.size(); } case Type::List: { - const auto& listData = std::get>(*_data); - - return listData->list.size(); + return std::get(_data).size(); } default: @@ -246,61 +549,76 @@ size_t Value::size() const void Value::emplace_back(std::string&& name, Value&& value) { - if (type() != Type::Map) + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::emplace_back for MapType"); } - auto& mapData = std::get>(*_data); + auto& mapData = std::get(_data); + const auto [itr, itrEnd] = std::equal_range(mapData.members.cbegin(), + mapData.members.cend(), + std::nullopt, + [&mapData, &name](std::optional lhs, std::optional rhs) noexcept { + std::string_view lhsName { lhs == std::nullopt ? name : mapData.map[*lhs].first }; + std::string_view rhsName { rhs == std::nullopt ? name : mapData.map[*rhs].first }; + return lhsName < rhsName; + }); - if (mapData->members.find(name) != mapData->members.cend()) + if (itr != itrEnd) { throw std::runtime_error("Duplicate Map member"); } - mapData->members.insert({ name, mapData->map.size() }); - mapData->map.emplace_back(std::make_pair(std::move(name), std::move(value))); + mapData.map.emplace_back(std::make_pair(std::move(name), std::move(value))); + mapData.members.insert(itr, mapData.members.size()); } -MapType::const_iterator Value::find(const std::string& name) const +MapType::const_iterator Value::find(std::string_view name) const { - if (type() != Type::Map) + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::find for MapType"); } - const auto& mapData = std::get>(*_data); - const auto itr = mapData->members.find(name); + const auto& mapData = std::get(_data); + const auto [itr, itrEnd] = std::equal_range(mapData.members.cbegin(), + mapData.members.cend(), + std::nullopt, + [&mapData, name](std::optional lhs, std::optional rhs) noexcept { + std::string_view lhsName { lhs == std::nullopt ? name : mapData.map[*lhs].first }; + std::string_view rhsName { rhs == std::nullopt ? name : mapData.map[*rhs].first }; + return lhsName < rhsName; + }); - if (itr == mapData->members.cend()) + if (itr == itrEnd) { - return mapData->map.cend(); + return mapData.map.cend(); } - return mapData->map.cbegin() + itr->second; + return mapData.map.cbegin() + *itr; } MapType::const_iterator Value::begin() const { - if (type() != Type::Map) + if (!std::holds_alternative(_data)) { - throw std::logic_error("Invalid call to Value::end for MapType"); + throw std::logic_error("Invalid call to Value::begin for MapType"); } - return std::get>(*_data)->map.cbegin(); + return std::get(_data).map.cbegin(); } MapType::const_iterator Value::end() const { - if (type() != Type::Map) + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::end for MapType"); } - return std::get>(*_data)->map.cend(); + return std::get(_data).map.cend(); } -const Value& Value::operator[](const std::string& name) const +const Value& Value::operator[](std::string_view name) const { const auto itr = find(name); @@ -314,226 +632,22 @@ const Value& Value::operator[](const std::string& name) const void Value::emplace_back(Value&& value) { - if (type() != Type::List) + if (!std::holds_alternative(_data)) { throw std::logic_error("Invalid call to Value::emplace_back for ListType"); } - std::get>(*_data)->list.emplace_back(std::move(value)); + std::get(_data).emplace_back(std::move(value)); } const Value& Value::operator[](size_t index) const { - if (type() != Type::List) - { - throw std::logic_error("Invalid call to Value::emplace_back for ListType"); - } - - return std::get>(*_data)->list.at(index); -} - -template <> -void Value::set(StringType&& value) -{ - if (type() != Type::String && type() != Type::EnumValue) - { - throw std::logic_error("Invalid call to Value::set for StringType"); - } - - std::get>(*_data)->string = std::move(value); -} - -template <> -void Value::set(BooleanType value) -{ - if (type() != Type::Boolean) + if (!std::holds_alternative(_data)) { - throw std::logic_error("Invalid call to Value::set for BooleanType"); + throw std::logic_error("Invalid call to Value::operator[] for ListType"); } - *_data = { value }; -} - -template <> -void Value::set(IntType value) -{ - if (type() == Type::Float) - { - // Coerce IntType to FloatType - *_data = { static_cast(value) }; - } - else - { - if (type() != Type::Int) - { - throw std::logic_error("Invalid call to Value::set for IntType"); - } - - *_data = { value }; - } -} - -template <> -void Value::set(FloatType value) -{ - if (type() != Type::Float) - { - throw std::logic_error("Invalid call to Value::set for FloatType"); - } - - *_data = { value }; -} - -template <> -void Value::set(ScalarType&& value) -{ - if (type() != Type::Scalar) - { - throw std::logic_error("Invalid call to Value::set for ScalarType"); - } - - *_data = { ScalarData { std::move(value) } }; -} - -template <> -const MapType& Value::get() const -{ - if (type() != Type::Map) - { - throw std::logic_error("Invalid call to Value::get for MapType"); - } - - return std::get>(*_data)->map; -} - -template <> -const ListType& Value::get() const -{ - if (type() != Type::List) - { - throw std::logic_error("Invalid call to Value::get for ListType"); - } - - return std::get>(*_data)->list; -} - -template <> -const StringType& Value::get() const -{ - if (type() != Type::String && type() != Type::EnumValue) - { - throw std::logic_error("Invalid call to Value::get for StringType"); - } - - return std::get>(*_data)->string; -} - -template <> -BooleanType Value::get() const -{ - if (type() != Type::Boolean) - { - throw std::logic_error("Invalid call to Value::get for BooleanType"); - } - - return std::get(*_data); -} - -template <> -IntType Value::get() const -{ - if (type() != Type::Int) - { - throw std::logic_error("Invalid call to Value::get for IntType"); - } - - return std::get(*_data); -} - -template <> -FloatType Value::get() const -{ - if (type() == Type::Int) - { - // Coerce IntType to FloatType - return static_cast(std::get(*_data)); - } - - if (type() != Type::Float) - { - throw std::logic_error("Invalid call to Value::get for FloatType"); - } - - return std::get(*_data); -} - -template <> -const ScalarType& Value::get() const -{ - if (type() != Type::Scalar) - { - throw std::logic_error("Invalid call to Value::get for ScalarType"); - } - - return std::get>(*_data)->scalar; -} - -template <> -MapType Value::release() -{ - if (type() != Type::Map) - { - throw std::logic_error("Invalid call to Value::release for MapType"); - } - - auto& mapData = std::get>(*_data); - MapType result = std::move(mapData->map); - - mapData->members.clear(); - - return result; -} - -template <> -ListType Value::release() -{ - if (type() != Type::List) - { - throw std::logic_error("Invalid call to Value::release for ListType"); - } - - ListType result = std::move(std::get>(*_data)->list); - - return result; -} - -template <> -StringType Value::release() -{ - if (type() != Type::String && type() != Type::EnumValue) - { - throw std::logic_error("Invalid call to Value::release for StringType"); - } - - auto& stringData = std::get>(*_data); - StringType result = std::move(stringData->string); - - stringData->from_json = false; - - return result; -} - -template <> -ScalarType Value::release() -{ - if (type() != Type::Scalar) - { - throw std::logic_error("Invalid call to Value::release for ScalarType"); - } - - ScalarType result = std::move(std::get>(*_data)->scalar); - - return result; + return std::get(_data).at(index); } } /* namespace graphql::response */ diff --git a/src/GraphQLSchema.cpp b/src/GraphQLSchema.cpp new file mode 100644 index 00000000..9faea3ed --- /dev/null +++ b/src/GraphQLSchema.cpp @@ -0,0 +1,593 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include "graphqlservice/GraphQLSchema.h" +#include "graphqlservice/introspection/IntrospectionSchema.h" + +using namespace std::literals; + +namespace graphql::schema { + +Schema::Schema(bool noIntrospection) + : _noIntrospection(noIntrospection) +{ +} + +void Schema::AddQueryType(std::shared_ptr query) +{ + _query = query; +} + +void Schema::AddMutationType(std::shared_ptr mutation) +{ + _mutation = mutation; +} + +void Schema::AddSubscriptionType(std::shared_ptr subscription) +{ + _subscription = subscription; +} + +void Schema::AddType(std::string_view name, std::shared_ptr type) +{ + _typeMap[name] = _types.size(); + _types.push_back({ name, type }); +} + +bool Schema::supportsIntrospection() const noexcept +{ + return !_noIntrospection; +} + +const std::shared_ptr& Schema::LookupType(std::string_view name) const +{ + auto itr = _typeMap.find(name); + + if (itr == _typeMap.cend()) + { + std::ostringstream message; + + message << "Type not found"; + + if (!name.empty()) + { + message << " name: " << name; + } + + throw service::schema_exception { { message.str() } }; + } + + return _types[itr->second].second; +} + +const std::shared_ptr& Schema::WrapType( + introspection::TypeKind kind, const std::shared_ptr& ofType) +{ + auto& wrappers = (kind == introspection::TypeKind::LIST) ? _listWrappers : _nonNullWrappers; + auto itr = wrappers.find(ofType); + + if (itr == wrappers.cend()) + { + std::tie(itr, std::ignore) = wrappers.insert({ ofType, WrapperType::Make(kind, ofType) }); + } + + return itr->second; +} + +void Schema::AddDirective(std::shared_ptr directive) +{ + _directives.emplace_back(std::move(directive)); +} + +const std::vector>>& Schema::types() + const noexcept +{ + return _types; +} + +const std::shared_ptr& Schema::queryType() const noexcept +{ + return _query; +} + +const std::shared_ptr& Schema::mutationType() const noexcept +{ + return _mutation; +} + +const std::shared_ptr& Schema::subscriptionType() const noexcept +{ + return _subscription; +} + +const std::vector>& Schema::directives() const noexcept +{ + return _directives; +} + +BaseType::BaseType(introspection::TypeKind kind, std::string_view description) + : _kind(kind) + , _description(description) +{ +} + +introspection::TypeKind BaseType::kind() const noexcept +{ + return _kind; +} + +std::string_view BaseType::name() const noexcept +{ + return ""sv; +} + +std::string_view BaseType::description() const noexcept +{ + return _description; +} + +const std::vector>& BaseType::fields() const noexcept +{ + static const std::vector> defaultValue {}; + return defaultValue; +} + +const std::vector>& BaseType::interfaces() const noexcept +{ + static const std::vector> defaultValue {}; + return defaultValue; +} + +const std::vector>& BaseType::possibleTypes() const noexcept +{ + static const std::vector> defaultValue {}; + return defaultValue; +} + +const std::vector>& BaseType::enumValues() const noexcept +{ + static const std::vector> defaultValue {}; + return defaultValue; +} + +const std::vector>& BaseType::inputFields() const noexcept +{ + static const std::vector> defaultValue {}; + return defaultValue; +} + +const std::weak_ptr& BaseType::ofType() const noexcept +{ + static const std::weak_ptr defaultValue; + return defaultValue; +} + +struct ScalarType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr ScalarType::Make(std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +ScalarType::ScalarType(init&& params) + : BaseType(introspection::TypeKind::SCALAR, params.description) + , _name(params.name) +{ +} + +std::string_view ScalarType::name() const noexcept +{ + return _name; +} + +struct ObjectType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr ObjectType::Make(std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +ObjectType::ObjectType(init&& params) + : BaseType(introspection::TypeKind::OBJECT, params.description) + , _name(params.name) +{ +} + +void ObjectType::AddInterfaces( + std::initializer_list> interfaces) +{ + _interfaces.resize(interfaces.size()); + std::copy(interfaces.begin(), interfaces.end(), _interfaces.begin()); + + for (const auto& interface : interfaces) + { + std::const_pointer_cast(interface)->AddPossibleType( + std::static_pointer_cast(shared_from_this())); + } +} + +void ObjectType::AddFields(std::initializer_list> fields) +{ + _fields.resize(fields.size()); + std::copy(fields.begin(), fields.end(), _fields.begin()); +} + +std::string_view ObjectType::name() const noexcept +{ + return _name; +} + +const std::vector>& ObjectType::fields() const noexcept +{ + return _fields; +} + +const std::vector>& ObjectType::interfaces() const noexcept +{ + return _interfaces; +} + +struct InterfaceType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr InterfaceType::Make( + std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +InterfaceType::InterfaceType(init&& params) + : BaseType(introspection::TypeKind::INTERFACE, params.description) + , _name(params.name) +{ +} + +void InterfaceType::AddPossibleType(std::weak_ptr possibleType) +{ + _possibleTypes.push_back(possibleType); +} + +void InterfaceType::AddFields(std::initializer_list> fields) +{ + _fields.resize(fields.size()); + std::copy(fields.begin(), fields.end(), _fields.begin()); +} + +std::string_view InterfaceType::name() const noexcept +{ + return _name; +} + +const std::vector>& InterfaceType::fields() const noexcept +{ + return _fields; +} + +const std::vector>& InterfaceType::possibleTypes() const noexcept +{ + return _possibleTypes; +} + +struct UnionType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr UnionType::Make(std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +UnionType::UnionType(init&& params) + : BaseType(introspection::TypeKind::UNION, params.description) + , _name(params.name) +{ +} + +void UnionType::AddPossibleTypes(std::initializer_list> possibleTypes) +{ + _possibleTypes.resize(possibleTypes.size()); + std::copy(possibleTypes.begin(), possibleTypes.end(), _possibleTypes.begin()); +} + +std::string_view UnionType::name() const noexcept +{ + return _name; +} + +const std::vector>& UnionType::possibleTypes() const noexcept +{ + return _possibleTypes; +} + +struct EnumType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr EnumType::Make(std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +EnumType::EnumType(init&& params) + : BaseType(introspection::TypeKind::ENUM, params.description) + , _name(params.name) +{ +} + +void EnumType::AddEnumValues(std::initializer_list enumValues) +{ + _enumValues.resize(enumValues.size()); + std::transform(enumValues.begin(), + enumValues.end(), + _enumValues.begin(), + [](const auto& value) { + return EnumValue::Make(value.value, value.description, value.deprecationReason); + }); +} + +std::string_view EnumType::name() const noexcept +{ + return _name; +} + +const std::vector>& EnumType::enumValues() const noexcept +{ + return _enumValues; +} + +struct InputObjectType::init +{ + std::string_view name; + std::string_view description; +}; + +std::shared_ptr InputObjectType::Make( + std::string_view name, std::string_view description) +{ + return std::make_shared(init { name, description }); +} + +InputObjectType::InputObjectType(init&& params) + : BaseType(introspection::TypeKind::INPUT_OBJECT, params.description) + , _name(params.name) +{ +} + +void InputObjectType::AddInputValues(std::initializer_list> inputValues) +{ + _inputValues.resize(inputValues.size()); + std::copy(inputValues.begin(), inputValues.end(), _inputValues.begin()); +} + +std::string_view InputObjectType::name() const noexcept +{ + return _name; +} + +const std::vector>& InputObjectType::inputFields() const noexcept +{ + return _inputValues; +} + +struct WrapperType::init +{ + introspection::TypeKind kind; + const std::shared_ptr& ofType; +}; + +std::shared_ptr WrapperType::Make( + introspection::TypeKind kind, const std::shared_ptr& ofType) +{ + return std::make_shared(init { kind, ofType }); +} + +WrapperType::WrapperType(init&& params) + : BaseType(params.kind, std::string_view()) + , _ofType(params.ofType) +{ +} + +const std::weak_ptr& WrapperType::ofType() const noexcept +{ + return _ofType; +} + +struct Field::init +{ + std::string_view name; + std::string_view description; + std::optional deprecationReason; + const std::shared_ptr& type; + std::vector> args; +}; + +std::shared_ptr Field::Make(std::string_view name, std::string_view description, + std::optional deprecationReason, const std::shared_ptr& type, + std::initializer_list> args) +{ + init params { name, description, deprecationReason, type }; + + params.args.resize(args.size()); + std::copy(args.begin(), args.end(), params.args.begin()); + + return std::make_shared(std::move(params)); +} + +Field::Field(init&& params) + : _name(params.name) + , _description(params.description) + , _deprecationReason(params.deprecationReason) + , _type(params.type) + , _args(std::move(params.args)) +{ +} + +std::string_view Field::name() const noexcept +{ + return _name; +} + +std::string_view Field::description() const noexcept +{ + return _description; +} + +const std::vector>& Field::args() const noexcept +{ + return _args; +} + +const std::weak_ptr& Field::type() const noexcept +{ + return _type; +} + +const std::optional& Field::deprecationReason() const noexcept +{ + return _deprecationReason; +} + +struct InputValue::init +{ + std::string_view name; + std::string_view description; + const std::shared_ptr& type; + std::string_view defaultValue; +}; + +std::shared_ptr InputValue::Make(std::string_view name, std::string_view description, + const std::shared_ptr& type, std::string_view defaultValue) +{ + return std::make_shared(init { name, description, type, defaultValue }); +} + +InputValue::InputValue(init&& params) + : _name(params.name) + , _description(params.description) + , _type(params.type) + , _defaultValue(params.defaultValue) +{ +} + +std::string_view InputValue::name() const noexcept +{ + return _name; +} + +std::string_view InputValue::description() const noexcept +{ + return _description; +} + +const std::weak_ptr& InputValue::type() const noexcept +{ + return _type; +} + +std::string_view InputValue::defaultValue() const noexcept +{ + return _defaultValue; +} + +struct EnumValue::init +{ + std::string_view name; + std::string_view description; + std::optional deprecationReason; +}; + +std::shared_ptr EnumValue::Make(std::string_view name, std::string_view description, + std::optional deprecationReason) +{ + return std::make_shared(init { name, description, deprecationReason }); +} + +EnumValue::EnumValue(init&& params) + : _name(params.name) + , _description(params.description) + , _deprecationReason(params.deprecationReason) +{ +} + +std::string_view EnumValue::name() const noexcept +{ + return _name; +} + +std::string_view EnumValue::description() const noexcept +{ + return _description; +} + +const std::optional& EnumValue::deprecationReason() const noexcept +{ + return _deprecationReason; +} + +struct Directive::init +{ + std::string_view name; + std::string_view description; + std::vector locations; + std::vector> args; +}; + +std::shared_ptr Directive::Make(std::string_view name, std::string_view description, + std::initializer_list locations, + std::initializer_list> args) +{ + init params { name, description }; + + params.locations.resize(locations.size()); + std::copy(locations.begin(), locations.end(), params.locations.begin()); + + params.args.resize(args.size()); + std::copy(args.begin(), args.end(), params.args.begin()); + + return std::make_shared(std::move(params)); +} + +Directive::Directive(init&& params) + : _name(params.name) + , _description(params.description) + , _locations(std::move(params.locations)) + , _args(std::move(params.args)) +{ +} + +std::string_view Directive::name() const noexcept +{ + return _name; +} + +std::string_view Directive::description() const noexcept +{ + return _description; +} + +const std::vector& Directive::locations() const noexcept +{ + return _locations; +} + +const std::vector>& Directive::args() const noexcept +{ + return _args; +} + +} // namespace graphql::schema diff --git a/src/GraphQLService.cpp b/src/GraphQLService.cpp index bf064b35..db27f215 100644 --- a/src/GraphQLService.cpp +++ b/src/GraphQLService.cpp @@ -9,7 +9,6 @@ #include #include #include -#include namespace graphql::service { @@ -41,7 +40,7 @@ void addErrorLocation(const schema_location& location, response::Value& error) error.emplace_back(std::string { strLocations }, std::move(errorLocations)); } -void addErrorPath(field_path&& path, response::Value& error) +void addErrorPath(const field_path& path, response::Value& error) { if (path.empty()) { @@ -51,21 +50,18 @@ void addErrorPath(field_path&& path, response::Value& error) response::Value errorPath(response::Type::List); errorPath.reserve(path.size()); - while (!path.empty()) + for (const auto& segment : path) { - auto& segment = path.front(); - - if (std::holds_alternative(segment)) + if (std::holds_alternative(segment)) { - errorPath.emplace_back(response::Value(std::move(std::get(segment)))); + errorPath.emplace_back( + response::Value { std::string { std::get(segment) } }); } else if (std::holds_alternative(segment)) { errorPath.emplace_back( response::Value(static_cast(std::get(segment)))); } - - path.pop(); } error.emplace_back(std::string { strPath }, std::move(errorPath)); @@ -84,7 +80,7 @@ response::Value buildErrorValues(const std::vector& structuredErro entry.reserve(3); addErrorMessage(std::move(error.message), entry); addErrorLocation(error.location, entry); - addErrorPath(std::move(error.path), entry); + addErrorPath(error.path, entry); errors.emplace_back(std::move(entry)); } @@ -94,7 +90,6 @@ response::Value buildErrorValues(const std::vector& structuredErro schema_exception::schema_exception(std::vector&& structuredErrors) : _structuredErrors(std::move(structuredErrors)) - , _errors(buildErrorValues(_structuredErrors)) { } @@ -122,24 +117,14 @@ const char* schema_exception::what() const noexcept { const char* message = nullptr; - if (_errors.size() > 0) + if (!_structuredErrors.empty()) { - auto itr = _errors[0].find("message"); - - if (itr != _errors[0].end() && itr->second.type() == response::Type::String) - { - message = itr->second.get().c_str(); - } + message = _structuredErrors.front().message.c_str(); } return (message == nullptr) ? "Unknown schema error" : message; } -const std::vector& schema_exception::getStructuredErrors() const noexcept -{ - return _structuredErrors; -} - std::vector schema_exception::getStructuredErrors() noexcept { auto structuredErrors = std::move(_structuredErrors); @@ -147,16 +132,9 @@ std::vector schema_exception::getStructuredErrors() noexcept return structuredErrors; } -const response::Value& schema_exception::getErrors() const noexcept +response::Value schema_exception::getErrors() const { - return _errors; -} - -response::Value schema_exception::getErrors() noexcept -{ - auto errors = std::move(_errors); - - return errors; + return buildErrorValues(_structuredErrors); } FieldParams::FieldParams(const SelectionSetParams& selectionSetParams, response::Value&& directives) @@ -739,7 +717,7 @@ void blockSubFields(const ResolverParams& params) } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -752,7 +730,7 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -765,7 +743,7 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -778,7 +756,7 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -791,7 +769,7 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -804,7 +782,7 @@ std::future ModifiedResult::convert( } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult&& result, ResolverParams&& params) { blockSubFields(params); @@ -833,7 +811,7 @@ void requireSubFields(const ResolverParams& params) } template <> -std::future ModifiedResult::convert( +std::future ModifiedResult::convert( FieldResult>&& result, ResolverParams&& params) { requireSubFields(params); @@ -845,12 +823,7 @@ std::future ModifiedResult::convert( if (!wrappedResult) { - response::Value document(response::Type::Map); - - document.emplace_back(std::string { strData }, - response::Value(response::Type::Null)); - - return document; + return ResolverResult {}; } return wrappedResult @@ -886,7 +859,7 @@ class SelectionVisitor void visit(const peg::ast_node& selection); - std::queue>> getValues(); + std::vector>> getValues(); private: void visitField(const peg::ast_node& field); @@ -903,9 +876,9 @@ class SelectionVisitor const TypeNames& _typeNames; const ResolverMap& _resolvers; - std::stack _fragmentDirectives; - std::unordered_set _names; - std::queue>> _values; + std::vector _fragmentDirectives; + std::unordered_set _names; + std::vector>> _values; }; SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams, @@ -921,12 +894,12 @@ SelectionVisitor::SelectionVisitor(const SelectionSetParams& selectionSetParams, , _typeNames(typeNames) , _resolvers(resolvers) { - _fragmentDirectives.push({ response::Value(response::Type::Map), + _fragmentDirectives.push_back({ response::Value(response::Type::Map), response::Value(response::Type::Map), response::Value(response::Type::Map) }); } -std::queue>> SelectionVisitor::getValues() +std::vector>> SelectionVisitor::getValues() { auto values = std::move(_values); @@ -951,13 +924,13 @@ void SelectionVisitor::visit(const peg::ast_node& selection) void SelectionVisitor::visitField(const peg::ast_node& field) { - std::string name; + std::string_view name; peg::on_first_child(field, [&name](const peg::ast_node& child) { name = child.string_view(); }); - std::string alias; + std::string_view alias; peg::on_first_child(field, [&alias](const peg::ast_node& child) { alias = child.string_view(); @@ -985,7 +958,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field) if (itr == itrEnd) { - std::promise promise; + std::promise promise; auto position = field.begin(); std::ostringstream error; @@ -994,7 +967,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field) promise.set_exception(std::make_exception_ptr(schema_exception { { schema_error { error.str(), { position.line, position.column }, { _path } } } })); - _values.push({ std::move(alias), promise.get_future() }); + _values.push_back({ alias, promise.get_future() }); return; } @@ -1030,15 +1003,15 @@ void SelectionVisitor::visitField(const peg::ast_node& field) auto path = _path; - path.push({ alias }); + path.push_back({ alias }); SelectionSetParams selectionSetParams { _resolverContext, _state, _operationDirectives, - _fragmentDirectives.top().fragmentDefinitionDirectives, - _fragmentDirectives.top().fragmentSpreadDirectives, - _fragmentDirectives.top().inlineFragmentDirectives, + _fragmentDirectives.back().fragmentDefinitionDirectives, + _fragmentDirectives.back().fragmentSpreadDirectives, + _fragmentDirectives.back().inlineFragmentDirectives, std::move(path), _launch, }; @@ -1054,11 +1027,11 @@ void SelectionVisitor::visitField(const peg::ast_node& field) _fragments, _variables)); - _values.push({ std::move(alias), std::move(result) }); + _values.push_back({ alias, std::move(result) }); } catch (schema_exception& scx) { - std::promise promise; + std::promise promise; auto position = field.begin(); auto messages = scx.getStructuredErrors(); @@ -1077,11 +1050,11 @@ void SelectionVisitor::visitField(const peg::ast_node& field) promise.set_exception(std::make_exception_ptr(schema_exception { std::move(messages) })); - _values.push({ std::move(alias), promise.get_future() }); + _values.push_back({ alias, promise.get_future() }); } catch (const std::exception& ex) { - std::promise promise; + std::promise promise; auto position = field.begin(); std::ostringstream message; @@ -1092,7 +1065,7 @@ void SelectionVisitor::visitField(const peg::ast_node& field) { position.line, position.column }, std::move(selectionSetParams.errorPath) } } })); - _values.push({ std::move(alias), promise.get_future() }); + _values.push_back({ alias, promise.get_future() }); } } @@ -1134,7 +1107,7 @@ void SelectionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) auto fragmentSpreadDirectives = directiveVisitor.getDirectives(); // Merge outer fragment spread directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.top().fragmentSpreadDirectives) + for (const auto& entry : _fragmentDirectives.back().fragmentSpreadDirectives) { if (fragmentSpreadDirectives.find(entry.first) == fragmentSpreadDirectives.end()) { @@ -1146,7 +1119,7 @@ void SelectionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) response::Value fragmentDefinitionDirectives(itr->second.getDirectives()); // Merge outer fragment definition directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.top().fragmentDefinitionDirectives) + for (const auto& entry : _fragmentDirectives.back().fragmentDefinitionDirectives) { if (fragmentDefinitionDirectives.find(entry.first) == fragmentDefinitionDirectives.end()) { @@ -1155,16 +1128,16 @@ void SelectionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) } } - _fragmentDirectives.push({ std::move(fragmentDefinitionDirectives), + _fragmentDirectives.push_back({ std::move(fragmentDefinitionDirectives), std::move(fragmentSpreadDirectives), - response::Value(_fragmentDirectives.top().inlineFragmentDirectives) }); + response::Value(_fragmentDirectives.back().inlineFragmentDirectives) }); for (const auto& selection : itr->second.getSelection().children) { visit(*selection); } - _fragmentDirectives.pop(); + _fragmentDirectives.pop_back(); } void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) @@ -1195,7 +1168,7 @@ void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) auto inlineFragmentDirectives = directiveVisitor.getDirectives(); // Merge outer inline fragment directives as long as they don't conflict. - for (const auto& entry : _fragmentDirectives.top().inlineFragmentDirectives) + for (const auto& entry : _fragmentDirectives.back().inlineFragmentDirectives) { if (inlineFragmentDirectives.find(entry.first) == inlineFragmentDirectives.end()) @@ -1205,9 +1178,9 @@ void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) } } - _fragmentDirectives.push( - { response::Value(_fragmentDirectives.top().fragmentDefinitionDirectives), - response::Value(_fragmentDirectives.top().fragmentSpreadDirectives), + _fragmentDirectives.push_back( + { response::Value(_fragmentDirectives.back().fragmentDefinitionDirectives), + response::Value(_fragmentDirectives.back().fragmentSpreadDirectives), std::move(inlineFragmentDirectives) }); for (const auto& selection : child.children) @@ -1215,7 +1188,7 @@ void SelectionVisitor::visitInlineFragment(const peg::ast_node& inlineFragment) visit(*selection); } - _fragmentDirectives.pop(); + _fragmentDirectives.pop_back(); }); } } @@ -1226,14 +1199,15 @@ Object::Object(TypeNames&& typeNames, ResolverMap&& resolvers) { } -std::future Object::resolve(const SelectionSetParams& selectionSetParams, +std::future Object::resolve(const SelectionSetParams& selectionSetParams, const peg::ast_node& selection, const FragmentMap& fragments, const response::Value& variables) const { - std::queue>> selections; + std::vector>> selections; beginSelectionSet(selectionSetParams); + selections.reserve(selection.children.size()); for (const auto& child : selection.children) { SelectionVisitor visitor(selectionSetParams, fragments, variables, _typeNames, _resolvers); @@ -1242,10 +1216,9 @@ std::future Object::resolve(const SelectionSetParams& selection auto values = visitor.getValues(); - while (!values.empty()) + for (auto& value : values) { - selections.push(std::move(values.front())); - values.pop(); + selections.push_back(std::move(value)); } } @@ -1253,63 +1226,56 @@ std::future Object::resolve(const SelectionSetParams& selection return std::async( selectionSetParams.launch, - [](std::queue>>&& children) { - response::Value data(response::Type::Map); - response::Value errors(response::Type::List); + [](std::vector>>&& children) { + ResolverResult document { response::Value { response::Type::Map } }; - while (!children.empty()) + for (auto& child : children) { - auto name = std::move(children.front().first); + auto name = child.first; try { - auto value = children.front().second.get(); - auto members = value.release(); + auto value = child.second.get(); + auto itrData = document.data.find(name); - for (auto& entry : members) + if (itrData == document.data.end()) { - if (entry.second.type() == response::Type::List && entry.first == strErrors) - { - auto errorEntries = entry.second.release(); + document.data.emplace_back(std::string { name }, std::move(value.data)); + } + else if (itrData->second != value.data) + { + std::ostringstream message; - for (auto& errorEntry : errorEntries) - { - errors.emplace_back(std::move(errorEntry)); - } - } - else if (entry.first == strData) + message << "Ambiguous field error name: " << name; + + document.errors.push_back({ message.str() }); + } + + if (!value.errors.empty()) + { + document.errors.reserve(document.errors.size() + value.errors.size()); + for (auto& error : value.errors) { - auto itrData = data.find(name); - - if (itrData == data.end()) - { - data.emplace_back(std::move(name), std::move(entry.second)); - } - else if (itrData->second != entry.second) - { - std::ostringstream message; - response::Value error(response::Type::Map); - - message << "Ambiguous field error name: " << name; - addErrorMessage(message.str(), error); - errors.emplace_back(std::move(error)); - } + document.errors.push_back(std::move(error)); } } } catch (schema_exception& scx) { - auto messages = scx.getErrors().release(); + auto errors = scx.getStructuredErrors(); - errors.reserve(errors.size() + messages.size()); - for (auto& error : messages) + if (!errors.empty()) { - errors.emplace_back(std::move(error)); + document.errors.reserve(document.errors.size() + errors.size()); + for (auto& error : errors) + { + document.errors.push_back(std::move(error)); + } } - if (data.find(name) == data.end()) + if (document.data.find(name) == document.data.end()) { - data.emplace_back(std::move(name), {}); + document.data.emplace_back(std::string { name }, {}); } } catch (const std::exception& ex) @@ -1318,30 +1284,16 @@ std::future Object::resolve(const SelectionSetParams& selection message << "Field error name: " << name << " unknown error: " << ex.what(); - response::Value error(response::Type::Map); - - addErrorMessage(message.str(), error); - errors.emplace_back(std::move(error)); + document.errors.push_back({ message.str() }); - if (data.find(name) == data.end()) + if (document.data.find(name) == document.data.end()) { - data.emplace_back(std::move(name), {}); + document.data.emplace_back(std::string { name }, {}); } } - - children.pop(); - } - - response::Value result(response::Type::Map); - - result.emplace_back(std::string { strData }, std::move(data)); - - if (errors.size() > 0) - { - result.emplace_back(std::string { strErrors }, std::move(errors)); } - return result; + return document; }, std::move(selections)); } @@ -1398,7 +1350,7 @@ FragmentMap FragmentDefinitionVisitor::getFragments() void FragmentDefinitionVisitor::visit(const peg::ast_node& fragmentDefinition) { - _fragments.insert({ fragmentDefinition.children.front()->string(), + _fragments.insert({ fragmentDefinition.children.front()->string_view(), Fragment(fragmentDefinition, _variables) }); } @@ -1411,16 +1363,16 @@ class OperationDefinitionVisitor std::shared_ptr state, const TypeMap& operations, response::Value&& variables, FragmentMap&& fragments); - std::future getValue(); + std::future getValue(); - void visit(const std::string& operationType, const peg::ast_node& operationDefinition); + void visit(std::string_view operationType, const peg::ast_node& operationDefinition); private: const ResolverContext _resolverContext; const std::launch _launch; std::shared_ptr _params; const TypeMap& _operations; - std::future _result; + std::future _result; }; OperationDefinitionVisitor::OperationDefinitionVisitor(ResolverContext resolverContext, @@ -1434,7 +1386,7 @@ OperationDefinitionVisitor::OperationDefinitionVisitor(ResolverContext resolverC { } -std::future OperationDefinitionVisitor::getValue() +std::future OperationDefinitionVisitor::getValue() { auto result = std::move(_result); @@ -1442,7 +1394,7 @@ std::future OperationDefinitionVisitor::getValue() } void OperationDefinitionVisitor::visit( - const std::string& operationType, const peg::ast_node& operationDefinition) + std::string_view operationType, const peg::ast_node& operationDefinition) { auto itr = _operations.find(operationType); @@ -1634,7 +1586,7 @@ void SubscriptionDefinitionVisitor::visit(const peg::ast_node& operationDefiniti void SubscriptionDefinitionVisitor::visitField(const peg::ast_node& field) { - std::string name; + std::string_view name; peg::on_first_child(field, [&name](const peg::ast_node& child) { name = child.string_view(); @@ -1685,7 +1637,7 @@ void SubscriptionDefinitionVisitor::visitField(const peg::ast_node& field) void SubscriptionDefinitionVisitor::visitFragmentSpread(const peg::ast_node& fragmentSpread) { - const std::string name(fragmentSpread.children.front()->string_view()); + const auto name = fragmentSpread.children.front()->string_view(); auto itr = _fragments.find(name); if (itr == _fragments.cend()) @@ -1757,9 +1709,9 @@ void SubscriptionDefinitionVisitor::visitInlineFragment(const peg::ast_node& inl } } -Request::Request(TypeMap&& operationTypes) +Request::Request(TypeMap&& operationTypes, const std::shared_ptr& schema) : _operations(std::move(operationTypes)) - , _validation(std::make_unique(*this)) + , _validation(std::make_unique(schema)) { } @@ -1784,93 +1736,185 @@ std::vector Request::validate(peg::ast& query) const return errors; } -std::pair Request::findOperationDefinition( - const peg::ast_node& root, const std::string& operationName) const +std::pair Request::findOperationDefinition( + peg::ast& query, std::string_view operationName) const { - bool hasAnonymous = false; - std::unordered_set usedNames; - std::pair result = { {}, nullptr }; + // Ensure the query has been validated. + auto errors = validate(query); + + if (!errors.empty()) + { + throw schema_exception { std::move(errors) }; + } + + std::pair result = { {}, nullptr }; - peg::for_each_child(root, - [this, &hasAnonymous, &usedNames, &operationName, &result]( - const peg::ast_node& operationDefinition) { - std::string operationType(strQuery); + peg::on_first_child_if(*query.root, + [this, &operationName, &result](const peg::ast_node& operationDefinition) noexcept -> bool { + std::string_view operationType = strQuery; peg::on_first_child(operationDefinition, [&operationType](const peg::ast_node& child) { operationType = child.string_view(); }); - std::string name; + std::string_view name; peg::on_first_child(operationDefinition, [&name](const peg::ast_node& child) { name = child.string_view(); }); - std::vector errors; - auto position = operationDefinition.begin(); - - // http://spec.graphql.org/June2018/#sec-Operation-Name-Uniqueness - if (!usedNames.insert(name).second) + if (operationName.empty() || name == operationName) { - std::ostringstream message; + result = { operationType, &operationDefinition }; + return true; + } - if (name.empty()) - { - message << "Multiple anonymous operations"; - } - else - { - message << "Duplicate named operations name: " << name; - } + return false; + }); - errors.push_back({ message.str(), { position.line, position.column } }); - } + return result; +} - hasAnonymous = hasAnonymous || name.empty(); +std::future Request::resolve(const std::shared_ptr& state, + peg::ast& query, const std::string& operationName, response::Value&& variables) const +{ + return resolve(std::launch::deferred, state, query, operationName, std::move(variables)); +} - // http://spec.graphql.org/June2018/#sec-Lone-Anonymous-Operation - if (name.empty() ? usedNames.size() > 1 : hasAnonymous) - { - std::ostringstream message; +std::future Request::resolve(std::launch launch, + const std::shared_ptr& state, peg::ast& query, const std::string& operationName, + response::Value&& variables) const +{ + try + { + FragmentDefinitionVisitor fragmentVisitor(variables); - if (name.empty()) - { - message << "Unexpected anonymous operation"; - } - else - { - message << "Unexpected named operation name: " << name; - } + peg::for_each_child(*query.root, + [&fragmentVisitor](const peg::ast_node& child) { + fragmentVisitor.visit(child); + }); + + auto fragments = fragmentVisitor.getFragments(); + auto operationDefinition = findOperationDefinition(query, operationName); + + if (!operationDefinition.second) + { + std::ostringstream message; - errors.push_back({ message.str(), { position.line, position.column } }); + message << "Missing operation"; + + if (!operationName.empty()) + { + message << " name: " << operationName; } - auto itr = _operations.find(operationType); + throw schema_exception { { message.str() } }; + } + else if (operationDefinition.first == strSubscription) + { + auto position = operationDefinition.second->begin(); + std::ostringstream message; - if (itr == _operations.cend()) + message << "Unexpected subscription"; + + if (!operationName.empty()) { - std::ostringstream message; + message << " name: " << operationName; + } - message << "Unsupported operation type: " << operationType; + throw schema_exception { + { schema_error { message.str(), { position.line, position.column } } } + }; + } + + const bool isMutation = (operationDefinition.first == strMutation); - if (!name.empty()) + // http://spec.graphql.org/June2018/#sec-Normal-and-Serial-Execution + if (isMutation) + { + // Force mutations to perform serial execution + launch = std::launch::deferred; + } + + const auto resolverContext = + isMutation ? ResolverContext::Mutation : ResolverContext::Query; + + OperationDefinitionVisitor operationVisitor(resolverContext, + launch, + state, + _operations, + std::move(variables), + std::move(fragments)); + + operationVisitor.visit(operationDefinition.first, *operationDefinition.second); + + return std::async( + launch, + [](std::future&& operationFuture) { + auto result = operationFuture.get(); + response::Value document { response::Type::Map }; + + document.emplace_back(std::string { strData }, std::move(result.data)); + + if (!result.errors.empty()) { - message << " name: " << name; + document.emplace_back(std::string { strErrors }, + buildErrorValues(result.errors)); } - errors.push_back({ message.str(), { position.line, position.column } }); - } + return document; + }, + operationVisitor.getValue()); + } + catch (schema_exception& ex) + { + std::promise promise; + response::Value document(response::Type::Map); - if (!errors.empty()) - { - throw schema_exception(std::move(errors)); - } - else if (operationName.empty() || name == operationName) + document.emplace_back(std::string { strData }, response::Value()); + document.emplace_back(std::string { strErrors }, ex.getErrors()); + promise.set_value(std::move(document)); + + return promise.get_future(); + } +} + +std::pair Request::findOperationDefinition( + const peg::ast_node& root, const std::string& operationName) const +{ + return findUnvalidatedOperationDefinition(root, operationName); +} + +std::pair Request::findUnvalidatedOperationDefinition( + const peg::ast_node& root, const std::string& operationName) const +{ + std::pair result = { {}, nullptr }; + + peg::on_first_child_if(root, + [&operationName, &result](const peg::ast_node& operationDefinition) { + auto operationType = strQuery; + + peg::on_first_child(operationDefinition, + [&operationType](const peg::ast_node& child) { + operationType = child.string_view(); + }); + + std::string_view name; + + peg::on_first_child(operationDefinition, + [&name](const peg::ast_node& child) { + name = child.string_view(); + }); + + if (operationName.empty() || name == operationName) { - result = { std::move(operationType), &operationDefinition }; + result = { std::string { operationType }, &operationDefinition }; + return true; } + + return false; }); return result; @@ -1879,7 +1923,7 @@ std::pair Request::findOperationDefinition( std::future Request::resolve(const std::shared_ptr& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const { - return resolveValidated(std::launch::deferred, + return resolveUnvalidated(std::launch::deferred, state, root, operationName, @@ -1890,59 +1934,15 @@ std::future Request::resolve(std::launch launch, const std::shared_ptr& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const { - return resolveValidated(launch, state, root, operationName, std::move(variables)); -} - -std::future Request::resolve(const std::shared_ptr& state, - peg::ast& query, const std::string& operationName, response::Value&& variables) const -{ - return resolve(std::launch::deferred, state, query, operationName, std::move(variables)); + return resolveUnvalidated(launch, state, root, operationName, std::move(variables)); } -std::future Request::resolve(std::launch launch, - const std::shared_ptr& state, peg::ast& query, const std::string& operationName, - response::Value&& variables) const -{ - auto errors = validate(query); - - if (!errors.empty()) - { - std::promise promise; - response::Value document(response::Type::Map); - - document.emplace_back(std::string { strData }, response::Value()); - document.emplace_back(std::string { strErrors }, buildErrorValues(errors)); - promise.set_value(std::move(document)); - - return promise.get_future(); - } - - return resolveValidated(launch, state, *query.root, operationName, std::move(variables)); -} - -std::future Request::resolveValidated(std::launch launch, +std::future Request::resolveUnvalidated(std::launch launch, const std::shared_ptr& state, const peg::ast_node& root, const std::string& operationName, response::Value&& variables) const { try { - // http://spec.graphql.org/June2018/#sec-Executable-Definitions - for (const auto& child : root.children) - { - if (!child->is_type() - && !child->is_type()) - { - auto position = child->begin(); - std::ostringstream message; - - message << "Unexpected type definition"; - - throw schema_exception { - { schema_error { message.str(), { position.line, position.column } } } - }; - } - } - FragmentDefinitionVisitor fragmentVisitor(variables); peg::for_each_child(root, @@ -1951,7 +1951,7 @@ std::future Request::resolveValidated(std::launch launch, }); auto fragments = fragmentVisitor.getFragments(); - auto operationDefinition = findOperationDefinition(root, operationName); + auto operationDefinition = findUnvalidatedOperationDefinition(root, operationName); if (!operationDefinition.second) { @@ -2004,7 +2004,23 @@ std::future Request::resolveValidated(std::launch launch, operationVisitor.visit(operationDefinition.first, *operationDefinition.second); - return operationVisitor.getValue(); + return std::async( + launch, + [](std::future&& operationFuture) { + auto result = operationFuture.get(); + response::Value document { response::Type::Map }; + + document.emplace_back(std::string { strData }, std::move(result.data)); + + if (!result.errors.empty()) + { + document.emplace_back(std::string { strErrors }, + buildErrorValues(result.errors)); + } + + return document; + }, + operationVisitor.getValue()); } catch (schema_exception& ex) { @@ -2036,7 +2052,7 @@ SubscriptionKey Request::subscribe(SubscriptionParams&& params, SubscriptionCall }); auto fragments = fragmentVisitor.getFragments(); - auto operationDefinition = findOperationDefinition(*params.query.root, params.operationName); + auto operationDefinition = findOperationDefinition(params.query, params.operationName); if (!operationDefinition.second) { @@ -2296,8 +2312,9 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, return; } - std::queue> callbacks; + std::vector> callbacks; + callbacks.reserve(itrListeners->second.size()); for (const auto& key : itrListeners->second) { auto itrSubscription = _subscriptions.find(key); @@ -2357,8 +2374,19 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, { result = std::async( launch, - [registration](std::future document) { - return document.get(); + [](std::future&& operationFuture) { + auto result = operationFuture.get(); + response::Value document { response::Type::Map }; + + document.emplace_back(std::string { strData }, std::move(result.data)); + + if (!result.errors.empty()) + { + document.emplace_back(std::string { strErrors }, + buildErrorValues(result.errors)); + } + + return document; }, optionalOrDefaultSubscription->resolve(selectionSetParams, registration->selection, @@ -2377,7 +2405,7 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, result = promise.get_future(); } - callbacks.push(std::async( + callbacks.push_back(std::async( launch, [registration](std::future document) { registration->callback(std::move(document)); @@ -2385,10 +2413,9 @@ void Request::deliver(std::launch launch, const SubscriptionName& name, std::move(result))); } - while (!callbacks.empty()) + for (auto& callback : callbacks) { - callbacks.front().get(); - callbacks.pop(); + callback.get(); } } diff --git a/src/GraphQLTree.cpp b/src/GraphQLTree.cpp index b184776c..9543f63a 100644 --- a/src/GraphQLTree.cpp +++ b/src/GraphQLTree.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include namespace graphql { diff --git a/src/Introspection.cpp b/src/Introspection.cpp index dba40012..7b7a12ef 100644 --- a/src/Introspection.cpp +++ b/src/Introspection.cpp @@ -1,636 +1,397 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" namespace graphql::introspection { -Schema::Schema() +Schema::Schema(const std::shared_ptr& schema) + : _schema(schema) { } -void Schema::AddQueryType(std::shared_ptr query) -{ - _query = std::move(query); -} - -void Schema::AddMutationType(std::shared_ptr mutation) -{ - _mutation = std::move(mutation); -} - -void Schema::AddSubscriptionType(std::shared_ptr subscription) -{ - _subscription = std::move(subscription); -} - -void Schema::AddType(response::StringType&& name, std::shared_ptr type) -{ - _typeMap[name] = _types.size(); - _types.push_back({ std::move(name), std::move(type) }); -} - -const std::shared_ptr& Schema::LookupType(const response::StringType& name) const -{ - auto itr = _typeMap.find(name); - - if (itr == _typeMap.cend()) - { - std::ostringstream message; - - message << "Type not found"; - - if (!name.empty()) - { - message << " name: " << name; - } - - throw service::schema_exception { { message.str() } }; - } - - return _types[itr->second].second; -} - -const std::shared_ptr& Schema::WrapType( - TypeKind kind, const std::shared_ptr& ofType) -{ - auto& wrappers = (kind == TypeKind::LIST) ? _listWrappers : _nonNullWrappers; - auto itr = wrappers.find(ofType); - - if (itr == wrappers.cend()) - { - std::tie(itr, std::ignore) = - wrappers.insert({ ofType, std::make_shared(kind, ofType) }); - } - - return itr->second; -} - -void Schema::AddDirective(std::shared_ptr directive) -{ - _directives.emplace_back(std::move(directive)); -} - service::FieldResult>> Schema::getTypes( service::FieldParams&& params) const { - auto spThis = shared_from_this(); + const auto& types = _schema->types(); + std::vector> result(types.size()); - return std::async(params.launch, [this, spThis]() { - std::vector> result(_types.size()); - - std::transform(_types.cbegin(), - _types.cend(), - result.begin(), - [](const std::pair>& namedType) { - return namedType.second; - }); - - return result; + std::transform(types.begin(), types.end(), result.begin(), [](const auto& entry) { + return std::make_shared(entry.second); }); + + return result; } service::FieldResult> Schema::getQueryType( service::FieldParams&&) const { - return _query; + const auto& queryType = _schema->queryType(); + + return queryType ? std::make_shared(queryType) : nullptr; } service::FieldResult> Schema::getMutationType( service::FieldParams&&) const { - return _mutation; -} + const auto& mutationType = _schema->mutationType(); -service::FieldResult> Schema::getSubscriptionType( - service::FieldParams&&) const -{ - return _subscription; + return mutationType ? std::make_shared(mutationType) : nullptr; } -service::FieldResult>> Schema::getDirectives( +service::FieldResult> Schema::getSubscriptionType( service::FieldParams&&) const { - return _directives; -} - -BaseType::BaseType(response::StringType&& description) - : _description(std::move(description)) -{ -} + const auto& subscriptionType = _schema->subscriptionType(); -service::FieldResult> BaseType::getName( - service::FieldParams&&) const -{ - return std::nullopt; + return subscriptionType ? std::make_shared(subscriptionType) : nullptr; } -service::FieldResult> BaseType::getDescription( +service::FieldResult>> Schema::getDirectives( service::FieldParams&&) const { - return { _description.empty() ? std::nullopt - : std::make_optional(_description) }; -} + const auto& directives = _schema->directives(); + std::vector> result(directives.size()); -service::FieldResult>>> -BaseType::getFields( - service::FieldParams&&, std::optional&& /*includeDeprecatedArg*/) const -{ - return std::nullopt; -} - -service::FieldResult>>> BaseType:: - getInterfaces(service::FieldParams&&) const -{ - return std::nullopt; -} + std::transform(directives.begin(), directives.end(), result.begin(), [](const auto& entry) { + return std::make_shared(entry); + }); -service::FieldResult>>> BaseType:: - getPossibleTypes(service::FieldParams&&) const -{ - return std::nullopt; + return result; } -service::FieldResult>>> -BaseType::getEnumValues( - service::FieldParams&&, std::optional&& /*includeDeprecatedArg*/) const +Type::Type(const std::shared_ptr& type) + : _type(type) { - return std::nullopt; } -service::FieldResult>>> BaseType:: - getInputFields(service::FieldParams&&) const +service::FieldResult Type::getKind(service::FieldParams&&) const { - return std::nullopt; + return _type->kind(); } -service::FieldResult> BaseType::getOfType( +service::FieldResult> Type::getName( service::FieldParams&&) const { - return std::shared_ptr {}; -} + const auto name = _type->name(); -ScalarType::ScalarType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ -} - -service::FieldResult ScalarType::getKind(service::FieldParams&&) const -{ - return TypeKind::SCALAR; + return { name.empty() ? std::nullopt : std::make_optional(name) }; } -service::FieldResult> ScalarType::getName( +service::FieldResult> Type::getDescription( service::FieldParams&&) const { - std::promise> promise; - - promise.set_value(std::make_optional(_name)); - - return promise.get_future(); -} + const auto description = _type->description(); -ObjectType::ObjectType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ + return { description.empty() ? std::nullopt + : std::make_optional(description) }; } -void ObjectType::AddInterfaces(std::vector> interfaces) +service::FieldResult>>> Type::getFields( + service::FieldParams&&, std::optional&& includeDeprecatedArg) const { - _interfaces = std::move(interfaces); - - for (const auto& interface : _interfaces) + switch (_type->kind()) { - interface->AddPossibleType(std::static_pointer_cast(shared_from_this())); - } -} + case introspection::TypeKind::OBJECT: + case introspection::TypeKind::INTERFACE: + break; -void ObjectType::AddFields(std::vector> fields) -{ - _fields = std::move(fields); -} - -service::FieldResult ObjectType::getKind(service::FieldParams&&) const -{ - return TypeKind::OBJECT; -} - -service::FieldResult> ObjectType::getName( - service::FieldParams&&) const -{ - return std::make_optional(_name); -} + default: + return std::nullopt; + } -service::FieldResult>>> ObjectType:: - getFields(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const -{ + const auto& fields = _type->fields(); const bool deprecated = includeDeprecatedArg && *includeDeprecatedArg; auto result = std::make_optional>>(); - result->reserve(_fields.size()); - std::copy_if(_fields.cbegin(), - _fields.cend(), - std::back_inserter(*result), - [¶ms, deprecated](const std::shared_ptr& field) { - return deprecated - || !field - ->getIsDeprecated( - service::FieldParams(params, response::Value(response::Type::Map))) - .get(); - }); - - return { std::move(result) }; -} - -service::FieldResult>>> ObjectType:: - getInterfaces(service::FieldParams&&) const -{ - auto result = - std::make_optional>>(_interfaces.size()); - - std::copy(_interfaces.cbegin(), _interfaces.cend(), result->begin()); - - return { std::move(result) }; -} - -InterfaceType::InterfaceType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ -} - -void InterfaceType::AddPossibleType(std::weak_ptr possibleType) -{ - _possibleTypes.push_back(possibleType); -} - -void InterfaceType::AddFields(std::vector> fields) -{ - _fields = std::move(fields); -} + result->reserve(fields.size()); + for (const auto& field : fields) + { + if (deprecated || !field->deprecationReason()) + { + result->push_back(std::make_shared(field)); + } + } -service::FieldResult InterfaceType::getKind(service::FieldParams&&) const -{ - return TypeKind::INTERFACE; + return result; } -service::FieldResult> InterfaceType::getName( +service::FieldResult>>> Type::getInterfaces( service::FieldParams&&) const { - return std::make_optional(_name); -} - -service::FieldResult>>> InterfaceType:: - getFields(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const -{ - const bool deprecated = includeDeprecatedArg && *includeDeprecatedArg; - auto result = std::make_optional>>(); - - result->reserve(_fields.size()); - std::copy_if(_fields.cbegin(), - _fields.cend(), - std::back_inserter(*result), - [¶ms, deprecated](const std::shared_ptr& field) { - return deprecated - || !field - ->getIsDeprecated( - service::FieldParams(params, response::Value(response::Type::Map))) - .get(); - }); - - return { std::move(result) }; -} - -service::FieldResult>>> InterfaceType:: - getPossibleTypes(service::FieldParams&&) const -{ - auto result = - std::make_optional>>(_possibleTypes.size()); + switch (_type->kind()) + { + case introspection::TypeKind::OBJECT: + break; - std::transform(_possibleTypes.cbegin(), - _possibleTypes.cend(), - result->begin(), - [](const std::weak_ptr& weak) { - return weak.lock(); - }); + default: + return std::nullopt; + } - return { std::move(result) }; -} + const auto& interfaces = _type->interfaces(); + auto result = std::make_optional>>(interfaces.size()); -UnionType::UnionType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ -} + std::transform(interfaces.begin(), interfaces.end(), result->begin(), [](const auto& entry) { + return std::make_shared(entry); + }); -void UnionType::AddPossibleTypes(std::vector> possibleTypes) -{ - _possibleTypes = std::move(possibleTypes); + return result; } -service::FieldResult UnionType::getKind(service::FieldParams&&) const +service::FieldResult>>> Type:: + getPossibleTypes(service::FieldParams&&) const { - return TypeKind::UNION; -} + switch (_type->kind()) + { + case introspection::TypeKind::INTERFACE: + case introspection::TypeKind::UNION: + break; -service::FieldResult> UnionType::getName( - service::FieldParams&&) const -{ - return std::make_optional(_name); -} + default: + return std::nullopt; + } -service::FieldResult>>> UnionType:: - getPossibleTypes(service::FieldParams&&) const -{ + const auto& possibleTypes = _type->possibleTypes(); auto result = - std::make_optional>>(_possibleTypes.size()); + std::make_optional>>(possibleTypes.size()); - std::transform(_possibleTypes.cbegin(), - _possibleTypes.cend(), + std::transform(possibleTypes.begin(), + possibleTypes.end(), result->begin(), - [](const std::weak_ptr& weak) { - return weak.lock(); + [](const auto& entry) { + return std::make_shared(entry.lock()); }); - return { std::move(result) }; -} - -EnumType::EnumType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ + return result; } -void EnumType::AddEnumValues(std::vector enumValues) +service::FieldResult>>> Type:: + getEnumValues( + service::FieldParams&&, std::optional&& includeDeprecatedArg) const { - _enumValues.reserve(_enumValues.size() + enumValues.size()); - - for (auto& value : enumValues) + switch (_type->kind()) { - _enumValues.push_back(std::make_shared(std::move(value.value), - std::move(value.description), - std::move(value.deprecationReason))); - } -} - -service::FieldResult EnumType::getKind(service::FieldParams&&) const -{ - return TypeKind::ENUM; -} + case introspection::TypeKind::ENUM: + break; -service::FieldResult> EnumType::getName( - service::FieldParams&&) const -{ - return std::make_optional(_name); -} + default: + return std::nullopt; + } -service::FieldResult>>> EnumType:: - getEnumValues(service::FieldParams&& params, - std::optional&& includeDeprecatedArg) const -{ + const auto& enumValues = _type->enumValues(); const bool deprecated = includeDeprecatedArg && *includeDeprecatedArg; auto result = std::make_optional>>(); - result->reserve(_enumValues.size()); - std::copy_if(_enumValues.cbegin(), - _enumValues.cend(), - std::back_inserter(*result), - [¶ms, deprecated](const std::shared_ptr& value) { - return deprecated - || !value - ->getIsDeprecated( - service::FieldParams(params, response::Value(response::Type::Map))) - .get(); - }); - - return { std::move(result) }; -} - -InputObjectType::InputObjectType(response::StringType&& name, response::StringType&& description) - : BaseType(std::move(description)) - , _name(std::move(name)) -{ -} + result->reserve(enumValues.size()); + for (const auto& value : enumValues) + { + if (deprecated || !value->deprecationReason()) + { + result->push_back(std::make_shared(value)); + } + } -void InputObjectType::AddInputValues(std::vector> inputValues) -{ - _inputValues = std::move(inputValues); + return result; } -service::FieldResult InputObjectType::getKind(service::FieldParams&&) const +service::FieldResult>>> Type:: + getInputFields(service::FieldParams&&) const { - return TypeKind::INPUT_OBJECT; -} + switch (_type->kind()) + { + case introspection::TypeKind::INPUT_OBJECT: + break; -service::FieldResult> InputObjectType::getName( - service::FieldParams&&) const -{ - return std::make_optional(_name); -} + default: + return std::nullopt; + } -service::FieldResult>>> -InputObjectType::getInputFields(service::FieldParams&&) const -{ + const auto& inputFields = _type->inputFields(); auto result = - std::make_optional>>(_inputValues.size()); + std::make_optional>>(inputFields.size()); - std::copy(_inputValues.cbegin(), _inputValues.cend(), result->begin()); + std::transform(inputFields.begin(), inputFields.end(), result->begin(), [](const auto& entry) { + return std::make_shared(entry); + }); - return { std::move(result) }; + return result; } -WrapperType::WrapperType(TypeKind kind, const std::shared_ptr& ofType) - : BaseType(response::StringType()) - , _kind(kind) - , _ofType(ofType) +service::FieldResult> Type::getOfType(service::FieldParams&&) const { -} + switch (_type->kind()) + { + case introspection::TypeKind::LIST: + case introspection::TypeKind::NON_NULL: + break; -service::FieldResult WrapperType::getKind(service::FieldParams&&) const -{ - return _kind; -} + default: + return nullptr; + } -service::FieldResult> WrapperType::getOfType( - service::FieldParams&&) const -{ - return _ofType.lock(); + const auto ofType = _type->ofType().lock(); + + return ofType ? std::make_shared(ofType) : nullptr; } -Field::Field(response::StringType&& name, response::StringType&& description, - std::optional&& deprecationReason, - std::vector>&& args, const std::shared_ptr& type) - : _name(std::move(name)) - , _description(std::move(description)) - , _deprecationReason(std::move(deprecationReason)) - , _args(std::move(args)) - , _type(type) +Field::Field(const std::shared_ptr& field) + : _field(field) { } service::FieldResult Field::getName(service::FieldParams&&) const { - return _name; + return response::StringType { _field->name() }; } service::FieldResult> Field::getDescription( service::FieldParams&&) const { - return { _description.empty() ? std::nullopt - : std::make_optional(_description) }; + const auto description = _field->description(); + + return { description.empty() ? std::nullopt + : std::make_optional(description) }; } service::FieldResult>> Field::getArgs( service::FieldParams&&) const { - std::vector> result(_args.size()); + const auto& args = _field->args(); + std::vector> result(args.size()); - std::copy(_args.cbegin(), _args.cend(), result.begin()); + std::transform(args.begin(), args.end(), result.begin(), [](const auto& entry) { + return std::make_shared(entry); + }); - return { std::move(result) }; + return result; } service::FieldResult> Field::getType(service::FieldParams&&) const { - return _type.lock(); + const auto type = _field->type().lock(); + + return type ? std::make_shared(type) : nullptr; } service::FieldResult Field::getIsDeprecated(service::FieldParams&&) const { - return _deprecationReason.has_value(); + return _field->deprecationReason().has_value(); } service::FieldResult> Field::getDeprecationReason( service::FieldParams&&) const { - return { _deprecationReason ? std::make_optional(*_deprecationReason) - : std::nullopt }; + const auto& deprecationReason = _field->deprecationReason(); + + return { deprecationReason ? std::make_optional(*deprecationReason) + : std::nullopt }; } -InputValue::InputValue(response::StringType&& name, response::StringType&& description, - const std::shared_ptr& type, response::StringType&& defaultValue) - : _name(std::move(name)) - , _description(std::move(description)) - , _type(type) - , _defaultValue(std::move(defaultValue)) +InputValue::InputValue(const std::shared_ptr& inputValue) + : _inputValue(inputValue) { } service::FieldResult InputValue::getName(service::FieldParams&&) const { - return _name; + return response::StringType { _inputValue->name() }; } service::FieldResult> InputValue::getDescription( service::FieldParams&&) const { - return { _description.empty() ? std::nullopt - : std::make_optional(_description) }; + const auto description = _inputValue->description(); + + return { description.empty() ? std::nullopt + : std::make_optional(description) }; } service::FieldResult> InputValue::getType( service::FieldParams&&) const { - return _type.lock(); + const auto type = _inputValue->type().lock(); + + return type ? std::make_shared(type) : nullptr; } service::FieldResult> InputValue::getDefaultValue( service::FieldParams&&) const { - return { _defaultValue.empty() ? std::nullopt - : std::make_optional(_defaultValue) }; + const auto defaultValue = _inputValue->defaultValue(); + + return { defaultValue.empty() ? std::nullopt + : std::make_optional(defaultValue) }; } -EnumValue::EnumValue(response::StringType&& name, response::StringType&& description, - std::optional&& deprecationReason) - : _name(std::move(name)) - , _description(std::move(description)) - , _deprecationReason(std::move(deprecationReason)) +EnumValue::EnumValue(const std::shared_ptr& enumValue) + : _enumValue(enumValue) { } service::FieldResult EnumValue::getName(service::FieldParams&&) const { - return _name; + return response::StringType { _enumValue->name() }; } service::FieldResult> EnumValue::getDescription( service::FieldParams&&) const { - return { _description.empty() ? std::nullopt - : std::make_optional(_description) }; + const auto description = _enumValue->description(); + + return { description.empty() ? std::nullopt + : std::make_optional(description) }; } service::FieldResult EnumValue::getIsDeprecated(service::FieldParams&&) const { - return _deprecationReason.has_value(); + return _enumValue->deprecationReason().has_value(); } service::FieldResult> EnumValue::getDeprecationReason( service::FieldParams&&) const { - return { _deprecationReason ? std::make_optional(*_deprecationReason) - : std::nullopt }; -} - -Directive::Directive(response::StringType&& name, response::StringType&& description, - std::vector&& locations, std::vector>&& args) - : _name(std::move(name)) - , _description(std::move(description)) - , _locations( - [](std::vector&& locationsArg) -> std::vector { - std::vector result(locationsArg.size()); + const auto& deprecationReason = _enumValue->deprecationReason(); - std::transform(locationsArg.begin(), - locationsArg.end(), - result.begin(), - [](std::string& name) -> DirectiveLocation { - response::Value location(response::Type::EnumValue); - - location.set(std::move(name)); - return service::ModifiedArgument::convert(location); - }); + return { deprecationReason ? std::make_optional(*deprecationReason) + : std::nullopt }; +} - return result; - }(std::move(locations))) - , _args(std::move(args)) +Directive::Directive(const std::shared_ptr& directive) + : _directive(directive) { } service::FieldResult Directive::getName(service::FieldParams&&) const { - return _name; + return response::StringType { _directive->name() }; } service::FieldResult> Directive::getDescription( service::FieldParams&&) const { - return { _description.empty() ? std::nullopt - : std::make_optional(_description) }; + const auto description = _directive->description(); + + return { description.empty() ? std::nullopt + : std::make_optional(description) }; } service::FieldResult> Directive::getLocations( service::FieldParams&&) const { - std::vector result(_locations.size()); - - std::copy(_locations.cbegin(), _locations.cend(), result.begin()); - - return { std::move(result) }; + return { _directive->locations() }; } service::FieldResult>> Directive::getArgs( service::FieldParams&&) const { - std::vector> result(_args.size()); + const auto& args = _directive->args(); + std::vector> result(args.size()); - std::copy(_args.cbegin(), _args.cend(), result.begin()); + std::transform(args.begin(), args.end(), result.begin(), [](const auto& entry) { + return std::make_shared(entry); + }); - return { std::move(result) }; + return result; } } /* namespace graphql::introspection */ diff --git a/src/JSONResponse.cpp b/src/JSONResponse.cpp index b4b05e6b..3bdcf180 100644 --- a/src/JSONResponse.cpp +++ b/src/JSONResponse.cpp @@ -11,8 +11,8 @@ #include #include -#include #include +#include namespace graphql::response { @@ -112,14 +112,14 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons ResponseHandler() { // Start with a single null value. - _responseStack.push({}); + _responseStack.push_back({}); } Value getResponse() { - auto response = std::move(_responseStack.top()); + auto response = std::move(_responseStack.back()); - _responseStack.pop(); + _responseStack.pop_back(); return response; } @@ -186,13 +186,13 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons bool StartObject() { - _responseStack.push(Value(Type::Map)); + _responseStack.push_back(Value(Type::Map)); return true; } bool Key(const Ch* str, rapidjson::SizeType /*length*/, bool /*copy*/) { - _keyStack.push(str); + _keyStack.push_back(str); return true; } @@ -204,7 +204,7 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons bool StartArray() { - _responseStack.push(Value(Type::List)); + _responseStack.push_back(Value(Type::List)); return true; } @@ -217,25 +217,25 @@ struct ResponseHandler : rapidjson::BaseReaderHandler, Respons private: void setValue(Value&& value) { - switch (_responseStack.top().type()) + switch (_responseStack.back().type()) { case Type::Map: - _responseStack.top().emplace_back(std::move(_keyStack.top()), std::move(value)); - _keyStack.pop(); + _responseStack.back().emplace_back(std::move(_keyStack.back()), std::move(value)); + _keyStack.pop_back(); break; case Type::List: - _responseStack.top().emplace_back(std::move(value)); + _responseStack.back().emplace_back(std::move(value)); break; default: - _responseStack.top() = std::move(value); + _responseStack.back() = std::move(value); break; } } - std::stack _keyStack; - std::stack _responseStack; + std::vector _keyStack; + std::vector _responseStack; }; Value parseJSON(const std::string& json) diff --git a/src/SchemaGenerator.cpp b/src/SchemaGenerator.cpp index b9ab1db1..ea139e5f 100644 --- a/src/SchemaGenerator.cpp +++ b/src/SchemaGenerator.cpp @@ -315,7 +315,7 @@ std::string Generator::getHeaderDir() const noexcept { if (_isIntrospection) { - return (fs::path { "include" } / "graphqlservice").string(); + return (fs::path { "include" } / "graphqlservice" / "introspection").string(); } else if (_options.paths) { @@ -1679,32 +1679,40 @@ bool Generator::outputHeader() const noexcept std::ofstream headerFile(_headerPath, std::ios_base::trunc); IncludeGuardScope includeGuard { headerFile, fs::path(_headerPath).filename().string() }; - headerFile << R"cpp(#include "graphqlservice/GraphQLService.h" + headerFile << R"cpp(#include "graphqlservice/GraphQLSchema.h" +#include "graphqlservice/GraphQLService.h" -#include +)cpp"; + if (_isIntrospection) + { + headerFile << + R"cpp(// clang-format off +#ifdef GRAPHQL_DLLEXPORTS + #ifdef IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllexport) + #else // !IMPL_GRAPHQLINTROSPECTION_DLL + #define GRAPHQLINTROSPECTION_EXPORT __declspec(dllimport) + #endif // !IMPL_GRAPHQLINTROSPECTION_DLL +#else // !GRAPHQL_DLLEXPORTS + #define GRAPHQLINTROSPECTION_EXPORT +#endif // !GRAPHQL_DLLEXPORTS +// clang-format on + +)cpp"; + } + + headerFile << + R"cpp(#include #include #include )cpp"; NamespaceScope graphqlNamespace { headerFile, "graphql" }; - NamespaceScope introspectionNamespace { headerFile, s_introspectionNamespace }; - NamespaceScope schemaNamespace { headerFile, _schemaNamespace, true }; + NamespaceScope schemaNamespace { headerFile, _schemaNamespace }; NamespaceScope objectNamespace { headerFile, "object", true }; PendingBlankLine pendingSeparator { headerFile }; - headerFile << R"cpp( -class Schema; -)cpp"; - - if (_options.separateFiles) - { - headerFile << R"cpp(class ObjectType; -)cpp"; - } - - headerFile << std::endl; - std::string queryType; if (!_isIntrospection) @@ -1717,11 +1725,6 @@ class Schema; break; } } - - introspectionNamespace.exit(); - headerFile << std::endl; - schemaNamespace.enter(); - pendingSeparator.add(); } if (!_enumTypes.empty()) @@ -1903,10 +1906,9 @@ class Schema; for (const auto& objectType : _objectTypes) { headerFile << R"cpp(void Add)cpp" << objectType.cppType - << R"cpp(Details(std::shared_ptr<)cpp" << s_introspectionNamespace - << R"cpp(::ObjectType> type)cpp" << objectType.cppType - << R"cpp(, const std::shared_ptr<)cpp" << s_introspectionNamespace - << R"cpp(::Schema>& schema); + << R"cpp(Details(std::shared_ptr type)cpp" + << objectType.cppType + << R"cpp(, const std::shared_ptr& schema); )cpp"; } @@ -1915,11 +1917,15 @@ class Schema; if (_isIntrospection) { - headerFile << R"cpp(GRAPHQLSERVICE_EXPORT )cpp"; + headerFile + << R"cpp(GRAPHQLINTROSPECTION_EXPORT void AddTypesToSchema(const std::shared_ptr& schema);)cpp"; + } + else + { + headerFile << R"cpp(std::shared_ptr GetSchema();)cpp"; } - headerFile << R"cpp(void AddTypesToSchema(const std::shared_ptr<)cpp" - << s_introspectionNamespace << R"cpp(::Schema>& schema); + headerFile << R"cpp( )cpp"; @@ -1977,17 +1983,16 @@ void Generator::outputObjectDeclaration( } headerFile << R"cpp( - std::future resolve_typename(service::ResolverParams&& params); + std::future resolve_typename(service::ResolverParams&& params); )cpp"; - if (isQueryType) + if (!_options.noIntrospection && isQueryType) { headerFile - << R"cpp( std::future resolve_schema(service::ResolverParams&& params); - std::future resolve_type(service::ResolverParams&& params); + << R"cpp( std::future resolve_schema(service::ResolverParams&& params); + std::future resolve_type(service::ResolverParams&& params); - std::shared_ptr<)cpp" - << s_introspectionNamespace << R"cpp(::Schema> _schema; + std::shared_ptr _schema; )cpp"; } } @@ -2042,7 +2047,7 @@ std::string Generator::getResolverDeclaration(const OutputField& outputField) co std::string fieldName(outputField.cppName); fieldName[0] = static_cast(std::toupper(static_cast(fieldName[0]))); - output << R"cpp( std::future resolve)cpp" << fieldName + output << R"cpp( std::future resolve)cpp" << fieldName << R"cpp((service::ResolverParams&& params); )cpp"; @@ -2065,7 +2070,7 @@ bool Generator::outputSource() const noexcept )cpp"; } - sourceFile << R"cpp(#include "graphqlservice/Introspection.h" + sourceFile << R"cpp(#include "graphqlservice/introspection/Introspection.h" #include #include @@ -2141,7 +2146,7 @@ template <> } template <> -std::future ModifiedResult<)cpp" +std::future ModifiedResult<)cpp" << _schemaNamespace << R"cpp(::)cpp" << enumType.cppType << R"cpp(>::convert(service::FieldResult<)cpp" << _schemaNamespace << R"cpp(::)cpp" << enumType.cppType @@ -2316,7 +2321,7 @@ Operations::Operations()cpp"; } sourceFile << R"cpp( - }) + }, GetSchema()) )cpp"; for (const auto& operation : _operationTypes) @@ -2336,8 +2341,7 @@ Operations::Operations()cpp"; sourceFile << std::endl; } - sourceFile << R"cpp(void AddTypesToSchema(const std::shared_ptr<)cpp" - << s_introspectionNamespace << R"cpp(::Schema>& schema) + sourceFile << R"cpp(void AddTypesToSchema(const std::shared_ptr& schema) { )cpp"; @@ -2346,10 +2350,16 @@ Operations::Operations()cpp"; // Add SCALAR types for each of the built-in types for (const auto& builtinType : s_builtinTypes) { - sourceFile << R"cpp( schema->AddType(")cpp" << builtinType.first - << R"cpp(", std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::ScalarType>(")cpp" << builtinType.first - << R"cpp(", R"md(Built-in type)md")); + sourceFile << R"cpp( schema->AddType(R"gql()cpp" << builtinType.first + << R"cpp()gql"sv, schema::ScalarType::Make(R"gql()cpp" << builtinType.first + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << R"cpp(Built-in type)cpp"; + } + + sourceFile << R"cpp()md")); )cpp"; } } @@ -2358,10 +2368,16 @@ Operations::Operations()cpp"; { for (const auto& scalarType : _scalarTypes) { - sourceFile << R"cpp( schema->AddType(")cpp" << scalarType.type - << R"cpp(", std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::ScalarType>(")cpp" << scalarType.type << R"cpp(", R"md()cpp" - << scalarType.description << R"cpp()md")); + sourceFile << R"cpp( schema->AddType(R"gql()cpp" << scalarType.type + << R"cpp()gql"sv, schema::ScalarType::Make(R"gql()cpp" << scalarType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << scalarType.description; + } + + sourceFile << R"cpp()md")); )cpp"; } } @@ -2371,11 +2387,17 @@ Operations::Operations()cpp"; for (const auto& enumType : _enumTypes) { sourceFile << R"cpp( auto type)cpp" << enumType.cppType - << R"cpp( = std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::EnumType>(")cpp" << enumType.type << R"cpp(", R"md()cpp" - << enumType.description << R"cpp()md"); - schema->AddType(")cpp" - << enumType.type << R"cpp(", type)cpp" << enumType.cppType << R"cpp(); + << R"cpp( = schema::EnumType::Make(R"gql()cpp" << enumType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << enumType.description; + } + + sourceFile << R"cpp()md"sv); + schema->AddType(R"gql()cpp" + << enumType.type << R"cpp()gql"sv, type)cpp" << enumType.cppType << R"cpp(); )cpp"; } } @@ -2385,11 +2407,18 @@ Operations::Operations()cpp"; for (const auto& inputType : _inputTypes) { sourceFile << R"cpp( auto type)cpp" << inputType.cppType - << R"cpp( = std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::InputObjectType>(")cpp" << inputType.type << R"cpp(", R"md()cpp" - << inputType.description << R"cpp()md"); - schema->AddType(")cpp" - << inputType.type << R"cpp(", type)cpp" << inputType.cppType << R"cpp(); + << R"cpp( = schema::InputObjectType::Make(R"gql()cpp" << inputType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << inputType.description; + } + + sourceFile << R"cpp()md"sv); + schema->AddType(R"gql()cpp" + << inputType.type << R"cpp()gql"sv, type)cpp" << inputType.cppType + << R"cpp(); )cpp"; } } @@ -2399,11 +2428,18 @@ Operations::Operations()cpp"; for (const auto& unionType : _unionTypes) { sourceFile << R"cpp( auto type)cpp" << unionType.cppType - << R"cpp( = std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::UnionType>(")cpp" << unionType.type << R"cpp(", R"md()cpp" - << unionType.description << R"cpp()md"); - schema->AddType(")cpp" - << unionType.type << R"cpp(", type)cpp" << unionType.cppType << R"cpp(); + << R"cpp( = schema::UnionType::Make(R"gql()cpp" << unionType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << unionType.description; + } + + sourceFile << R"cpp()md"sv); + schema->AddType(R"gql()cpp" + << unionType.type << R"cpp()gql"sv, type)cpp" << unionType.cppType + << R"cpp(); )cpp"; } } @@ -2413,11 +2449,17 @@ Operations::Operations()cpp"; for (const auto& interfaceType : _interfaceTypes) { sourceFile << R"cpp( auto type)cpp" << interfaceType.cppType - << R"cpp( = std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::InterfaceType>(")cpp" << interfaceType.type << R"cpp(", R"md()cpp" - << interfaceType.description << R"cpp()md"); - schema->AddType(")cpp" - << interfaceType.type << R"cpp(", type)cpp" << interfaceType.cppType + << R"cpp( = schema::InterfaceType::Make(R"gql()cpp" << interfaceType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << interfaceType.description; + } + + sourceFile << R"cpp()md"sv); + schema->AddType(R"gql()cpp" + << interfaceType.type << R"cpp()gql"sv, type)cpp" << interfaceType.cppType << R"cpp(); )cpp"; } @@ -2428,11 +2470,18 @@ Operations::Operations()cpp"; for (const auto& objectType : _objectTypes) { sourceFile << R"cpp( auto type)cpp" << objectType.cppType - << R"cpp( = std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::ObjectType>(")cpp" << objectType.type << R"cpp(", R"md()cpp" - << objectType.description << R"cpp()md"); - schema->AddType(")cpp" - << objectType.type << R"cpp(", type)cpp" << objectType.cppType << R"cpp(); + << R"cpp( = schema::ObjectType::Make(R"gql()cpp" << objectType.type + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << objectType.description; + } + + sourceFile << R"cpp()md"); + schema->AddType(R"gql()cpp" + << objectType.type << R"cpp()gql"sv, type)cpp" << objectType.cppType + << R"cpp(); )cpp"; } } @@ -2459,16 +2508,22 @@ Operations::Operations()cpp"; } firstValue = false; - sourceFile << R"cpp( { std::string{ service::s_names)cpp" - << enumType.cppType << R"cpp([static_cast()cpp" - << _schemaNamespace << R"cpp(::)cpp" << enumType.cppType - << R"cpp(::)cpp" << enumValue.cppValue << R"cpp()] }, R"md()cpp" - << enumValue.description << R"cpp()md", )cpp"; + sourceFile << R"cpp( { service::s_names)cpp" << enumType.cppType + << R"cpp([static_cast()cpp" << _schemaNamespace + << R"cpp(::)cpp" << enumType.cppType << R"cpp(::)cpp" + << enumValue.cppValue << R"cpp()], R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << enumValue.description; + } + + sourceFile << R"cpp()md"sv, )cpp"; if (enumValue.deprecationReason) { - sourceFile << R"cpp(std::make_optional(R"md()cpp" - << *enumValue.deprecationReason << R"cpp()md"))cpp"; + sourceFile << R"cpp(std::make_optional(R"md()cpp" + << *enumValue.deprecationReason << R"cpp()md"sv))cpp"; } else { @@ -2507,12 +2562,18 @@ Operations::Operations()cpp"; } firstValue = false; - sourceFile << R"cpp( std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::InputValue>(")cpp" << inputField.name - << R"cpp(", R"md()cpp" << inputField.description << R"cpp()md", )cpp" + sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" + << inputField.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << inputField.description; + } + + sourceFile << R"cpp()md"sv, )cpp" << getIntrospectionType(inputField.type, inputField.modifiers) << R"cpp(, R"gql()cpp" << inputField.defaultValueString - << R"cpp()gql"))cpp"; + << R"cpp()gql"sv))cpp"; } sourceFile << R"cpp( @@ -2532,8 +2593,7 @@ Operations::Operations()cpp"; { bool firstValue = true; - sourceFile << R"cpp( type)cpp" << unionType.cppType - << R"cpp(->AddPossibleTypes({ + sourceFile << R"cpp( type)cpp" << unionType.cppType << R"cpp(->AddPossibleTypes({ )cpp"; for (const auto& unionOption : unionType.options) @@ -2545,8 +2605,8 @@ Operations::Operations()cpp"; } firstValue = false; - sourceFile << R"cpp( schema->LookupType(")cpp" << unionOption - << R"cpp("))cpp"; + sourceFile << R"cpp( schema->LookupType(R"gql()cpp" << unionOption + << R"cpp()gql"sv))cpp"; } sourceFile << R"cpp( @@ -2578,29 +2638,35 @@ Operations::Operations()cpp"; } firstValue = false; - sourceFile << R"cpp( std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::Field>(")cpp" << interfaceField.name - << R"cpp(", R"md()cpp" << interfaceField.description - << R"cpp()md", )cpp"; + sourceFile << R"cpp( schema::Field::Make(R"gql()cpp" + << interfaceField.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << interfaceField.description; + } + + sourceFile << R"cpp()md"sv, )cpp"; if (interfaceField.deprecationReason) { - sourceFile << R"cpp(std::make_optional(R"md()cpp" - << *interfaceField.deprecationReason << R"cpp()md"))cpp"; + sourceFile << R"cpp(std::make_optional(R"md()cpp" + << *interfaceField.deprecationReason << R"cpp()md"sv))cpp"; } else { sourceFile << R"cpp(std::nullopt)cpp"; } - sourceFile << R"cpp(, std::vector>()cpp"; + sourceFile << R"cpp(, )cpp" + << getIntrospectionType(interfaceField.type, + interfaceField.modifiers); if (!interfaceField.arguments.empty()) { bool firstArgument = true; - sourceFile << R"cpp({ + sourceFile << R"cpp(, { )cpp"; for (const auto& argument : interfaceField.arguments) @@ -2612,23 +2678,25 @@ Operations::Operations()cpp"; } firstArgument = false; - sourceFile << R"cpp( std::make_shared<)cpp" - << s_introspectionNamespace << R"cpp(::InputValue>(")cpp" - << argument.name << R"cpp(", R"md()cpp" - << argument.description << R"cpp()md", )cpp" + sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" + << argument.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << argument.description; + } + + sourceFile << R"cpp()md"sv, )cpp" << getIntrospectionType(argument.type, argument.modifiers) << R"cpp(, R"gql()cpp" << argument.defaultValueString - << R"cpp()gql"))cpp"; + << R"cpp()gql"sv))cpp"; } sourceFile << R"cpp( })cpp"; } - sourceFile << R"cpp(), )cpp" - << getIntrospectionType(interfaceField.type, - interfaceField.modifiers) - << R"cpp())cpp"; + sourceFile << R"cpp())cpp"; } sourceFile << R"cpp( @@ -2663,16 +2731,21 @@ Operations::Operations()cpp"; for (const auto& directive : _directives) { - sourceFile << R"cpp( schema->AddDirective(std::make_shared<)cpp" - << s_introspectionNamespace << R"cpp(::Directive>(")cpp" << directive.name - << R"cpp(", R"md()cpp" << directive.description - << R"cpp()md", std::vector()cpp"; + sourceFile << R"cpp( schema->AddDirective(schema::Directive::Make(R"gql()cpp" + << directive.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << directive.description; + } + + sourceFile << R"cpp()md"sv, {)cpp"; if (!directive.locations.empty()) { bool firstLocation = true; - sourceFile << R"cpp({ + sourceFile << R"cpp( )cpp"; for (const auto& location : directive.locations) @@ -2684,21 +2757,21 @@ Operations::Operations()cpp"; } firstLocation = false; - sourceFile << R"cpp( R"gql()cpp" << location << R"cpp()gql")cpp"; + sourceFile << R"cpp( )cpp" << s_introspectionNamespace + << R"cpp(::DirectiveLocation::)cpp" << location; } sourceFile << R"cpp( - })cpp"; + )cpp"; } - sourceFile << R"cpp(), std::vector>()cpp"; + sourceFile << R"cpp(})cpp"; if (!directive.arguments.empty()) { bool firstArgument = true; - sourceFile << R"cpp({ + sourceFile << R"cpp(, { )cpp"; for (const auto& argument : directive.arguments) @@ -2710,18 +2783,24 @@ Operations::Operations()cpp"; } firstArgument = false; - sourceFile << R"cpp( std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::InputValue>(")cpp" << argument.name << R"cpp(", R"md()cpp" - << argument.description << R"cpp()md", )cpp" + sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" + << argument.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << argument.description; + } + + sourceFile << R"cpp()md"sv, )cpp" << getIntrospectionType(argument.type, argument.modifiers) << R"cpp(, R"gql()cpp" << argument.defaultValueString - << R"cpp()gql"))cpp"; + << R"cpp()gql"sv))cpp"; } sourceFile << R"cpp( })cpp"; } - sourceFile << R"cpp())); + sourceFile << R"cpp()); )cpp"; } } @@ -2746,6 +2825,29 @@ Operations::Operations()cpp"; )cpp"; + if (!_isIntrospection) + { + sourceFile << R"cpp(std::shared_ptr GetSchema() +{ + static std::weak_ptr s_wpSchema; + auto schema = s_wpSchema.lock(); + + if (!schema) + { + schema = std::make_shared()cpp" + << (_options.noIntrospection ? "true" : "false") << R"cpp(); + )cpp" << s_introspectionNamespace + << R"cpp(::AddTypesToSchema(schema); + AddTypesToSchema(schema); + s_wpSchema = schema; + } + + return schema; +} + +)cpp"; + } + return true; } @@ -2800,7 +2902,7 @@ void Generator::outputObjectImplementation( resolvers["__typename"sv] = R"cpp( { R"gql(__typename)gql"sv, [this](service::ResolverParams&& params) { return resolve_typename(std::move(params)); } })cpp"s; - if (isQueryType) + if (!_options.noIntrospection && isQueryType) { resolvers["__schema"sv] = R"cpp( { R"gql(__schema)gql"sv, [this](service::ResolverParams&& params) { return resolve_schema(std::move(params)); } })cpp"s; @@ -2825,27 +2927,15 @@ void Generator::outputObjectImplementation( sourceFile << R"cpp( }))cpp"; - if (isQueryType) + if (!_options.noIntrospection && isQueryType) { sourceFile << R"cpp( - , _schema(std::make_shared<)cpp" - << s_introspectionNamespace << R"cpp(::Schema>()))cpp"; + , _schema(GetSchema()))cpp"; } sourceFile << R"cpp( { -)cpp"; - - if (isQueryType) - { - sourceFile << R"cpp( )cpp" << s_introspectionNamespace - << R"cpp(::AddTypesToSchema(_schema); - )cpp" << _schemaNamespace - << R"cpp(::AddTypesToSchema(_schema); -)cpp"; - } - - sourceFile << R"cpp(} +} )cpp"; // Output each of the resolver implementations, which call the virtual property @@ -2877,7 +2967,7 @@ service::FieldResult<)cpp" } sourceFile << R"cpp( -std::future )cpp" +std::future )cpp" << objectType.cppType << R"cpp(::resolve)cpp" << fieldName << R"cpp((service::ResolverParams&& params) { @@ -2956,7 +3046,7 @@ std::future )cpp" } sourceFile << R"cpp( -std::future )cpp" +std::future )cpp" << objectType.cppType << R"cpp(::resolve_typename(service::ResolverParams&& params) { return service::ModifiedResult::convert(response::StringType{ R"gql()cpp" @@ -2964,24 +3054,30 @@ std::future )cpp" } )cpp"; - if (isQueryType) + if (!_options.noIntrospection && isQueryType) { sourceFile << R"cpp( -std::future )cpp" +std::future )cpp" << objectType.cppType << R"cpp(::resolve_schema(service::ResolverParams&& params) { - return service::ModifiedResult::convert(std::static_pointer_cast(_schema), std::move(params)); + return service::ModifiedResult::convert(std::static_pointer_cast(std::make_shared<)cpp" + << s_introspectionNamespace << R"cpp(::Schema>(_schema)), std::move(params)); } -std::future )cpp" +std::future )cpp" << objectType.cppType << R"cpp(::resolve_type(service::ResolverParams&& params) { auto argName = service::ModifiedArgument::require("name", params.arguments); + const auto& baseType = _schema->LookupType(argName); + std::shared_ptr<)cpp" + << s_introspectionNamespace + << R"cpp(::object::Type> result { baseType ? std::make_shared<)cpp" + << s_introspectionNamespace << R"cpp(::Type>(baseType) : nullptr }; return service::ModifiedResult<)cpp" << s_introspectionNamespace - << R"cpp(::object::Type>::convert(_schema->LookupType(argName), std::move(params)); + << R"cpp(::object::Type>::convert(result, std::move(params)); } )cpp"; } @@ -3009,10 +3105,9 @@ void Generator::outputObjectIntrospection( if (_options.separateFiles) { - sourceFile << R"cpp( std::static_pointer_cast<)cpp" - << s_introspectionNamespace - << R"cpp(::InterfaceType>(schema->LookupType(")cpp" << interfaceName - << R"cpp(")))cpp"; + sourceFile + << R"cpp( std::static_pointer_cast(schema->LookupType(R"gql()cpp" + << interfaceName << R"cpp()gql"sv)))cpp"; } else { @@ -3041,28 +3136,34 @@ void Generator::outputObjectIntrospection( } firstValue = false; - sourceFile << R"cpp( std::make_shared<)cpp" << s_introspectionNamespace - << R"cpp(::Field>(")cpp" << objectField.name << R"cpp(", R"md()cpp" - << objectField.description << R"cpp()md", )cpp"; + sourceFile << R"cpp( schema::Field::Make(R"gql()cpp" << objectField.name + << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << objectField.description; + } + + sourceFile << R"cpp()md"sv, )cpp"; if (objectField.deprecationReason) { - sourceFile << R"cpp(std::make_optional(R"md()cpp" - << *objectField.deprecationReason << R"cpp()md"))cpp"; + sourceFile << R"cpp(std::make_optional(R"md()cpp" << *objectField.deprecationReason + << R"cpp()md"sv))cpp"; } else { sourceFile << R"cpp(std::nullopt)cpp"; } - sourceFile << R"cpp(, std::vector>()cpp"; + sourceFile << R"cpp(, )cpp" + << getIntrospectionType(objectField.type, objectField.modifiers); if (!objectField.arguments.empty()) { bool firstArgument = true; - sourceFile << R"cpp({ + sourceFile << R"cpp(, { )cpp"; for (const auto& argument : objectField.arguments) @@ -3074,22 +3175,25 @@ void Generator::outputObjectIntrospection( } firstArgument = false; - sourceFile << R"cpp( std::make_shared<)cpp" - << s_introspectionNamespace << R"cpp(::InputValue>(")cpp" - << argument.name << R"cpp(", R"md()cpp" << argument.description - << R"cpp()md", )cpp" + sourceFile << R"cpp( schema::InputValue::Make(R"gql()cpp" + << argument.name << R"cpp()gql"sv, R"md()cpp"; + + if (!_options.noIntrospection) + { + sourceFile << argument.description; + } + + sourceFile << R"cpp()md"sv, )cpp" << getIntrospectionType(argument.type, argument.modifiers) << R"cpp(, R"gql()cpp" << argument.defaultValueString - << R"cpp()gql"))cpp"; + << R"cpp()gql"sv))cpp"; } sourceFile << R"cpp( })cpp"; } - sourceFile << R"cpp(), )cpp" - << getIntrospectionType(objectField.type, objectField.modifiers) - << R"cpp())cpp"; + sourceFile << R"cpp())cpp"; } sourceFile << R"cpp( @@ -3517,7 +3621,7 @@ std::vector Generator::outputSeparateFiles() const noexcept #include ")cpp" << fs::path(_objectHeaderPath).filename().string() << R"cpp(" -#include "graphqlservice/Introspection.h" +#include "graphqlservice/introspection/Introspection.h" #include #include @@ -3540,10 +3644,8 @@ using namespace std::literals; sourceFile << std::endl; sourceFile << R"cpp(void Add)cpp" << objectType.cppType - << R"cpp(Details(std::shared_ptr<)cpp" << s_introspectionNamespace - << R"cpp(::ObjectType> type)cpp" << objectType.cppType - << R"cpp(, const std::shared_ptr<)cpp" << s_introspectionNamespace - << R"cpp(::Schema>& schema) + << R"cpp(Details(std::shared_ptr type)cpp" + << objectType.cppType << R"cpp(, const std::shared_ptr& schema) { )cpp"; outputObjectIntrospection(sourceFile, objectType); @@ -3581,6 +3683,7 @@ int main(int argc, char** argv) bool noStubs = false; bool verbose = false; bool separateFiles = false; + bool noIntrospection = false; std::string schemaFileName; std::string filenamePrefix; std::string schemaNamespace; @@ -3604,7 +3707,9 @@ int main(int argc, char** argv) po::bool_switch(&noStubs), "Generate abstract classes without stub implementations")("separate-files", po::bool_switch(&separateFiles), - "Generate separate files for each of the types"); + "Generate separate files for each of the types")("no-introspection", + po::bool_switch(&noIntrospection), + "Do not generate support for Introspection"); positional.add("schema", 1).add("prefix", 1).add("namespace", 1); internalOptions.add_options()("introspection", po::bool_switch(&buildIntrospection), @@ -3675,7 +3780,8 @@ int main(int argc, char** argv) graphql::schema::GeneratorPaths { std::move(headerDir), std::move(sourceDir) }, verbose, separateFiles, - noStubs }) + noStubs, + noIntrospection }) .Build(); for (const auto& file : files) diff --git a/src/Validation.cpp b/src/Validation.cpp index b25a2dbe..a5f886e2 100644 --- a/src/Validation.cpp +++ b/src/Validation.cpp @@ -2,6 +2,7 @@ // Licensed under the MIT License. #include "graphqlservice/GraphQLGrammar.h" +#include "graphqlservice/introspection/IntrospectionSchema.h" #include "Validation.h" @@ -9,8 +10,27 @@ #include #include +using namespace std::literals; + namespace graphql::service { +SharedType getSharedType(const ValidateType& type) noexcept +{ + return type ? type->get().shared_from_this() : SharedType {}; +} + +ValidateType getValidateType(const SharedType& type) noexcept +{ + return type ? std::make_optional(std::cref(*type)) : std::nullopt; +} + +bool operator==(const ValidateType& lhs, const ValidateType& rhs) noexcept +{ + // Equal if they're either both std::nullopt or they are both not empty and the addresses of the + // references match. + return (lhs ? (rhs && &lhs->get() == &rhs->get()) : !rhs); +} + bool ValidateArgumentVariable::operator==(const ValidateArgumentVariable& other) const { return name == other.name; @@ -130,7 +150,7 @@ void ValidateArgumentValueVisitor::visit(const peg::ast_node& value) void ValidateArgumentValueVisitor::visitVariable(const peg::ast_node& variable) { - ValidateArgumentVariable value { std::string { variable.string_view().substr(1) } }; + ValidateArgumentVariable value { variable.string_view().substr(1) }; auto position = variable.begin(); _argumentValue.value = std::make_unique(std::move(value)); @@ -183,7 +203,7 @@ void ValidateArgumentValueVisitor::visitNullValue(const peg::ast_node& nullValue void ValidateArgumentValueVisitor::visitEnumValue(const peg::ast_node& enumValue) { - ValidateArgumentEnumValue value { enumValue.string() }; + ValidateArgumentEnumValue value { enumValue.string_view() }; auto position = enumValue.begin(); _argumentValue.value = std::make_unique(std::move(value)); @@ -216,7 +236,7 @@ void ValidateArgumentValueVisitor::visitObjectValue(const peg::ast_node& objectV for (const auto& field : objectValue.children) { - auto name = field->children.front()->string(); + auto name = field->children.front()->string_view(); if (value.values.find(name) != value.values.end()) { @@ -240,8 +260,8 @@ void ValidateArgumentValueVisitor::visitObjectValue(const peg::ast_node& objectV _argumentValue.position = { position.line, position.column }; } -ValidateField::ValidateField(std::string&& returnType, std::optional&& objectType, - const std::string& fieldName, ValidateFieldArguments&& arguments) +ValidateField::ValidateField(ValidateType&& returnType, ValidateType&& objectType, + std::string_view fieldName, ValidateFieldArguments&& arguments) : returnType(std::move(returnType)) , objectType(std::move(objectType)) , fieldName(fieldName) @@ -251,17 +271,16 @@ ValidateField::ValidateField(std::string&& returnType, std::optionalget() != &other.objectType->get()) || (fieldName == other.fieldName && arguments == other.arguments)); } -ValidateVariableTypeVisitor::ValidateVariableTypeVisitor(const ValidateTypeKinds& typeKinds) - : _typeKinds(typeKinds) - , _variableType(response::Type::Map) +ValidateVariableTypeVisitor::ValidateVariableTypeVisitor( + const std::shared_ptr& schema, const ValidateTypes& types) + : _schema(schema) + , _types(types) { - // kind and either name or ofType - _variableType.reserve(2); } void ValidateVariableTypeVisitor::visit(const peg::ast_node& typeName) @@ -282,61 +301,46 @@ void ValidateVariableTypeVisitor::visit(const peg::ast_node& typeName) void ValidateVariableTypeVisitor::visitNamedType(const peg::ast_node& namedType) { - auto name = namedType.string(); - auto itrKind = _typeKinds.find(name); + auto name = namedType.string_view(); + auto itrType = _types.find(name); - if (itrKind == _typeKinds.end()) + if (itrType == _types.end()) { return; } - response::Value kind(response::Type::EnumValue); - - switch (itrKind->second) + switch (itrType->second->get().kind()) { case introspection::TypeKind::SCALAR: - kind.set(R"gql(SCALAR)gql"); - break; - case introspection::TypeKind::ENUM: - kind.set(R"gql(ENUM)gql"); - break; - case introspection::TypeKind::INPUT_OBJECT: - kind.set(R"gql(INPUT_OBJECT)gql"); + _isInputType = true; + _variableType = getValidateType(_schema->LookupType(name)); break; default: - return; + break; } - - _isInputType = true; - _variableType.emplace_back(R"gql(kind)gql", std::move(kind)); - _variableType.emplace_back(R"gql(name)gql", response::Value(std::move(name))); } void ValidateVariableTypeVisitor::visitListType(const peg::ast_node& listType) { - response::Value kind(response::Type::EnumValue); - ValidateVariableTypeVisitor visitor(_typeKinds); + ValidateVariableTypeVisitor visitor(_schema, _types); - kind.set(R"gql(LIST)gql"); visitor.visit(*listType.children.front()); _isInputType = visitor.isInputType(); - _variableType.emplace_back(R"gql(kind)gql", std::move(kind)); - _variableType.emplace_back(R"gql(ofType)gql", visitor.getType()); + _variableType = getValidateType( + _schema->WrapType(introspection::TypeKind::LIST, getSharedType(visitor.getType()))); } void ValidateVariableTypeVisitor::visitNonNullType(const peg::ast_node& nonNullType) { - response::Value kind(response::Type::EnumValue); - ValidateVariableTypeVisitor visitor(_typeKinds); + ValidateVariableTypeVisitor visitor(_schema, _types); - kind.set(R"gql(NON_NULL)gql"); visitor.visit(*nonNullType.children.front()); _isInputType = visitor.isInputType(); - _variableType.emplace_back(R"gql(kind)gql", std::move(kind)); - _variableType.emplace_back(R"gql(ofType)gql", visitor.getType()); + _variableType = getValidateType( + _schema->WrapType(introspection::TypeKind::NON_NULL, getSharedType(visitor.getType()))); } bool ValidateVariableTypeVisitor::isInputType() const @@ -351,329 +355,105 @@ ValidateType ValidateVariableTypeVisitor::getType() return result; } -ValidateExecutableVisitor::ValidateExecutableVisitor(const Request& service) - : _service(service) +ValidateExecutableVisitor::ValidateExecutableVisitor(const std::shared_ptr& schema) + : _schema(schema) { - auto data = executeQuery(R"gql(query { - __schema { - queryType { - name - } - mutationType { - name - } - subscriptionType { - name - } - types { - name - kind - possibleTypes { - name - } - enumValues(includeDeprecated: true) { - name - } - } - directives { - name - locations - args { - name - defaultValue - type { - ...nestedType - } - } - } - } - } + const auto& queryType = _schema->queryType(); + const auto& mutationType = _schema->mutationType(); + const auto& subscriptionType = _schema->subscriptionType(); - fragment nestedType on __Type { - kind - name - ofType { - ...nestedType - } - })gql"); - auto members = data.release(); - auto itrData = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(__schema)gql"; - }); + if (queryType) + { + _operationTypes[strQuery] = getValidateType(queryType); + } + + if (mutationType) + { + _operationTypes[strMutation] = getValidateType(mutationType); + } + + if (subscriptionType) + { + _operationTypes[strSubscription] = getValidateType(subscriptionType); + } + + const auto& types = _schema->types(); - if (itrData != members.end() && itrData->second.type() == response::Type::Map) + for (const auto& entry : types) { - members = itrData->second.release(); + const auto name = entry.first; + const auto kind = entry.second->kind(); - for (auto& member : members) + if (!isScalarType(kind)) { - if (member.second.type() == response::Type::Map) + if (kind == introspection::TypeKind::OBJECT) { - auto typeMembers = member.second.release(); - auto itrType = std::find_if(typeMembers.begin(), - typeMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - - if (itrType != typeMembers.end() - && itrType->second.type() == response::Type::String) - { - if (member.first == R"gql(queryType)gql") - { - _operationTypes[strQuery] = itrType->second.release(); - } - else if (member.first == R"gql(mutationType)gql") - { - _operationTypes[strMutation] = - itrType->second.release(); - } - else if (member.first == R"gql(subscriptionType)gql") - { - _operationTypes[strSubscription] = - itrType->second.release(); - } - } + _matchingTypes[name].insert(name); } - else if (member.second.type() == response::Type::List - && member.first == R"gql(types)gql") + else { - auto entries = member.second.release(); + const auto& possibleTypes = entry.second->possibleTypes(); + std::set matchingTypes; - for (auto& entry : entries) + for (const auto& possibleType : possibleTypes) { - if (entry.type() != response::Type::Map) - { - continue; - } + const auto spType = possibleType.lock(); - auto typeMembers = entry.release(); - auto itrName = std::find_if(typeMembers.begin(), - typeMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - auto itrKind = std::find_if(typeMembers.begin(), - typeMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(kind)gql"; - }); - - if (itrName != typeMembers.end() - && itrName->second.type() == response::Type::String - && itrKind != typeMembers.end() - && itrKind->second.type() == response::Type::EnumValue) + if (spType) { - auto name = itrName->second.release(); - auto kind = - ModifiedArgument::convert(itrKind->second); - - if (!isScalarType(kind)) - { - if (kind == introspection::TypeKind::OBJECT) - { - _matchingTypes[name].insert(name); - } - else - { - auto itrPossibleTypes = std::find_if(typeMembers.begin(), - typeMembers.end(), - [](const std::pair& - entry) noexcept { - return entry.first == R"gql(possibleTypes)gql"; - }); - - if (itrPossibleTypes != typeMembers.end() - && itrPossibleTypes->second.type() == response::Type::List) - { - std::set matchingTypes; - auto matchingTypeEntries = - itrPossibleTypes->second.release(); - - for (auto& matchingTypeEntry : matchingTypeEntries) - { - if (matchingTypeEntry.type() != response::Type::Map) - { - continue; - } - - auto matchingTypeMembers = - matchingTypeEntry.release(); - auto itrMatchingTypeName = - std::find_if(matchingTypeMembers.begin(), - matchingTypeMembers.end(), - [](const std::pair& - entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - - if (itrMatchingTypeName != matchingTypeMembers.end() - && itrMatchingTypeName->second.type() - == response::Type::String) - { - matchingTypes.insert( - itrMatchingTypeName->second - .release()); - } - } - - if (!matchingTypes.empty()) - { - _matchingTypes[name] = std::move(matchingTypes); - } - } - } - } - else if (kind == introspection::TypeKind::ENUM) - { - auto itrEnumValues = std::find_if(typeMembers.begin(), - typeMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(enumValues)gql"; - }); - - if (itrEnumValues != typeMembers.end() - && itrEnumValues->second.type() == response::Type::List) - { - std::set enumValues; - auto enumValuesEntries = - itrEnumValues->second.release(); - - for (auto& enumValuesEntry : enumValuesEntries) - { - if (enumValuesEntry.type() != response::Type::Map) - { - continue; - } - - auto enumValuesMembers = - enumValuesEntry.release(); - auto itrEnumValuesName = std::find_if(enumValuesMembers.begin(), - enumValuesMembers.end(), - [](const std::pair& - entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - - if (itrEnumValuesName != enumValuesMembers.end() - && itrEnumValuesName->second.type() - == response::Type::String) - { - enumValues.insert(itrEnumValuesName->second - .release()); - } - } - - if (!enumValues.empty()) - { - _enumValues[name] = std::move(enumValues); - } - } - } - else if (kind == introspection::TypeKind::SCALAR) - { - _scalarTypes.insert(name); - } - - _typeKinds[std::move(name)] = kind; + matchingTypes.insert(spType->name()); } } - } - else if (member.second.type() == response::Type::List - && member.first == R"gql(directives)gql") - { - auto entries = member.second.release(); - for (auto& entry : entries) + if (!matchingTypes.empty()) { - if (entry.type() != response::Type::Map) - { - continue; - } - - auto directiveMembers = entry.release(); - auto itrName = std::find_if(directiveMembers.begin(), - directiveMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - auto itrLocations = std::find_if(directiveMembers.begin(), - directiveMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(locations)gql"; - }); - - if (itrName != directiveMembers.end() - && itrName->second.type() == response::Type::String - && itrLocations != directiveMembers.end() - && itrLocations->second.type() == response::Type::List) - { - ValidateDirective directive; - auto locations = itrLocations->second.release(); - - for (const auto& location : locations) - { - if (location.type() != response::Type::EnumValue) - { - continue; - } - - directive.locations.insert( - ModifiedArgument::convert( - location)); - } - - auto itrArgs = std::find_if(directiveMembers.begin(), - directiveMembers.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(args)gql"; - }); - - if (itrArgs != directiveMembers.end() - && itrArgs->second.type() == response::Type::List) - { - directive.arguments = - getArguments(itrArgs->second.release()); - } + _matchingTypes[name] = std::move(matchingTypes); + } + } + } + else if (kind == introspection::TypeKind::ENUM) + { + const auto& enumValues = entry.second->enumValues(); + std::set values; - _directives[itrName->second.release()] = - std::move(directive); - } + for (const auto& value : enumValues) + { + if (value) + { + values.insert(value->name()); } } + + if (!enumValues.empty()) + { + _enumValues[name] = std::move(values); + } + } + else if (kind == introspection::TypeKind::SCALAR) + { + _scalarTypes.insert(name); } + + _types[name] = getValidateType(entry.second); } -} -response::Value ValidateExecutableVisitor::executeQuery(std::string_view query) const -{ - auto ast = peg::parseString(query); - - // This is taking advantage of the fact that during validation we can choose to execute - // unvalidated queries against the Introspection schema. This way we can use fragment - // cycles to expand an arbitrary number of wrapper types. - ast.validated = true; - - response::Value data(response::Type::Map); - std::shared_ptr state; - const std::string operationName; - response::Value variables(response::Type::Map); - auto result = _service.resolve(state, ast, operationName, std::move(variables)).get(); - auto members = result.release(); - auto itrResponse = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == strData; - }); + const auto& directives = _schema->directives(); - if (itrResponse != members.end()) + for (const auto& directive : directives) { - data = std::move(itrResponse->second); - } + const auto name = directive->name(); + const auto& locations = directive->locations(); + const auto& args = directive->args(); + ValidateDirective validateDirective; + + for (const auto location : locations) + { + validateDirective.locations.insert(location); + } - return data; + validateDirective.arguments = getArguments(args); + _directives[name] = std::move(validateDirective); + } } void ValidateExecutableVisitor::visit(const peg::ast_node& root) @@ -683,7 +463,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) [this](const peg::ast_node& fragmentDefinition) { const auto& fragmentName = fragmentDefinition.children.front(); const auto inserted = - _fragmentDefinitions.insert({ fragmentName->string(), fragmentDefinition }); + _fragmentDefinitions.insert({ fragmentName->string_view(), fragmentDefinition }); if (!inserted.second) { @@ -698,36 +478,35 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) }); // Visit all of the operation definitions and check for duplicates. - peg::for_each_child(root, - [this](const peg::ast_node& operationDefinition) { - std::string operationName; + peg::for_each_child< + peg::operation_definition>(root, [this](const peg::ast_node& operationDefinition) { + std::string_view operationName; - peg::on_first_child(operationDefinition, - [&operationName](const peg::ast_node& child) { - operationName = child.string_view(); - }); + peg::on_first_child(operationDefinition, + [&operationName](const peg::ast_node& child) { + operationName = child.string_view(); + }); - const auto inserted = - _operationDefinitions.insert({ std::move(operationName), operationDefinition }); + const auto inserted = _operationDefinitions.insert({ operationName, operationDefinition }); - if (!inserted.second) - { - // http://spec.graphql.org/June2018/#sec-Operation-Name-Uniqueness - auto position = operationDefinition.begin(); - std::ostringstream error; + if (!inserted.second) + { + // http://spec.graphql.org/June2018/#sec-Operation-Name-Uniqueness + auto position = operationDefinition.begin(); + std::ostringstream error; - error << "Duplicate operation name: " << inserted.first->first; + error << "Duplicate operation name: " << inserted.first->first; - _errors.push_back({ error.str(), { position.line, position.column } }); - } - }); + _errors.push_back({ error.str(), { position.line, position.column } }); + } + }); // Check for lone anonymous operations. if (_operationDefinitions.size() > 1) { auto itr = std::find_if(_operationDefinitions.cbegin(), _operationDefinitions.cend(), - [](const std::pair& entry) noexcept { + [](const auto& entry) noexcept { return entry.first.empty(); }); @@ -776,8 +555,7 @@ void ValidateExecutableVisitor::visit(const peg::ast_node& root) std::transform(unreferencedFragments.cbegin(), unreferencedFragments.cend(), _errors.begin() + originalSize, - [](const std::pair& - fragmentDefinition) noexcept { + [](const auto& fragmentDefinition) noexcept { auto position = fragmentDefinition.second.begin(); std::ostringstream message; @@ -807,22 +585,22 @@ void ValidateExecutableVisitor::visitFragmentDefinition(const peg::ast_node& fra visitDirectives(introspection::DirectiveLocation::FRAGMENT_DEFINITION, child); }); - const auto name = fragmentDefinition.children.front()->string(); + const auto name = fragmentDefinition.children.front()->string_view(); const auto& selection = *fragmentDefinition.children.back(); const auto& typeCondition = fragmentDefinition.children[1]; - auto innerType = typeCondition->children.front()->string(); + auto innerType = typeCondition->children.front()->string_view(); - auto itrKind = _typeKinds.find(innerType); + auto itrType = _types.find(innerType); - if (itrKind == _typeKinds.end() || isScalarType(itrKind->second)) + if (itrType == _types.end() || isScalarType(itrType->second->get().kind())) { // http://spec.graphql.org/June2018/#sec-Fragment-Spread-Type-Existence // http://spec.graphql.org/June2018/#sec-Fragments-On-Composite-Types auto position = typeCondition->begin(); std::ostringstream message; - message << (itrKind == _typeKinds.end() ? "Undefined target type on fragment definition: " - : "Scalar target type on fragment definition: ") + message << (itrType == _types.end() ? "Undefined target type on fragment definition: " + : "Scalar target type on fragment definition: ") << name << " name: " << innerType; _errors.push_back({ message.str(), { position.line, position.column } }); @@ -830,11 +608,11 @@ void ValidateExecutableVisitor::visitFragmentDefinition(const peg::ast_node& fra } _fragmentStack.insert(name); - _scopedType = std::move(innerType); + _scopedType = itrType->second; visitSelection(selection); - _scopedType.clear(); + _scopedType.reset(); _fragmentStack.clear(); _selectionFields.clear(); } @@ -848,7 +626,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op operationType = child.string_view(); }); - std::string operationName; + std::string_view operationName; peg::on_first_child(operationDefinition, [&operationName](const peg::ast_node& child) { @@ -858,8 +636,8 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op _operationVariables = std::make_optional(); peg::for_each_child(operationDefinition, - [this, &operationName](const peg::ast_node& variable) { - std::string variableName; + [this, operationName](const peg::ast_node& variable) { + std::string_view variableName; ValidateArgument variableArgument; for (const auto& child : variable.children) @@ -891,7 +669,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op else if (child->is_type() || child->is_type() || child->is_type()) { - ValidateVariableTypeVisitor visitor(_typeKinds); + ValidateVariableTypeVisitor visitor(_schema, _types); visitor.visit(*child); @@ -949,7 +727,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op } _variableDefinitions.insert({ variableName, variable }); - _operationVariables->insert({ std::move(variableName), std::move(variableArgument) }); + _operationVariables->insert({ variableName, std::move(variableArgument) }); }); peg::on_first_child(operationDefinition, @@ -1004,7 +782,7 @@ void ValidateExecutableVisitor::visitOperationDefinition(const peg::ast_node& op _errors.push_back({ error.str(), { position.line, position.column } }); } - _scopedType.clear(); + _scopedType.reset(); _fragmentStack.clear(); _selectionFields.clear(); @@ -1046,65 +824,31 @@ void ValidateExecutableVisitor::visitSelection(const peg::ast_node& selection) } } -ValidateTypeFieldArguments ValidateExecutableVisitor::getArguments(response::ListType&& args) +ValidateTypeFieldArguments ValidateExecutableVisitor::getArguments( + const std::vector>& args) { ValidateTypeFieldArguments result; - for (auto& arg : args) + for (const auto& arg : args) { - if (arg.type() != response::Type::Map) + if (!arg) { continue; } - auto members = arg.release(); - auto itrName = std::find_if(members.begin(), - members.end(), - [](const std::pair& argEntry) noexcept { - return argEntry.first == R"gql(name)gql"; - }); - auto itrType = std::find_if(members.begin(), - members.end(), - [](const std::pair& argEntry) noexcept { - return argEntry.first == R"gql(type)gql"; - }); - auto itrDefaultValue = std::find_if(members.begin(), - members.end(), - [](const std::pair& argEntry) noexcept { - return argEntry.first == R"gql(defaultValue)gql"; - }); - - if (itrName != members.end() && itrName->second.type() == response::Type::String - && itrType != members.end() && itrType->second.type() == response::Type::Map) - { - ValidateArgument argument; + ValidateArgument argument; - argument.defaultValue = (itrDefaultValue != members.end() - && itrDefaultValue->second.type() == response::Type::String); - argument.nonNullDefaultValue = argument.defaultValue - && itrDefaultValue->second.get() != R"gql(null)gql"; - argument.type = std::move(itrType->second); + argument.defaultValue = !arg->defaultValue().empty(); + argument.nonNullDefaultValue = + argument.defaultValue && arg->defaultValue() != R"gql(null)gql"sv; + argument.type = getValidateType(arg->type().lock()); - result[itrName->second.release()] = std::move(argument); - } + result[arg->name()] = std::move(argument); } return result; } -std::optional ValidateExecutableVisitor::getTypeKind( - const std::string& name) const -{ - auto itrKind = _typeKinds.find(name); - - return (itrKind == _typeKinds.cend() ? std::nullopt : std::make_optional(itrKind->second)); -} - -std::optional ValidateExecutableVisitor::getScopedTypeKind() const -{ - return getTypeKind(_scopedType); -} - constexpr bool ValidateExecutableVisitor::isScalarType(introspection::TypeKind kind) { switch (kind) @@ -1119,21 +863,21 @@ constexpr bool ValidateExecutableVisitor::isScalarType(introspection::TypeKind k } } -bool ValidateExecutableVisitor::matchesScopedType(const std::string& name) const +bool ValidateExecutableVisitor::matchesScopedType(std::string_view name) const { - if (name == _scopedType) + if (name == _scopedType->get().name()) { return true; } - auto itrScoped = _matchingTypes.find(_scopedType); - auto itrNamed = _matchingTypes.find(name); + const auto itrScoped = _matchingTypes.find(_scopedType->get().name()); + const auto itrNamed = _matchingTypes.find(name); if (itrScoped != _matchingTypes.end() && itrNamed != _matchingTypes.end()) { - auto itrMatch = std::find_if(itrScoped->second.begin(), + const auto itrMatch = std::find_if(itrScoped->second.begin(), itrScoped->second.end(), - [this, itrNamed](const std::string& matchingType) noexcept { + [this, itrNamed](std::string_view matchingType) noexcept { return itrNamed->second.find(matchingType) != itrNamed->second.end(); }); @@ -1146,7 +890,7 @@ bool ValidateExecutableVisitor::matchesScopedType(const std::string& name) const bool ValidateExecutableVisitor::validateInputValue( bool hasNonNullDefaultValue, const ValidateArgumentValuePtr& argument, const ValidateType& type) { - if (type.type() != response::Type::Map) + if (!type) { _errors.push_back({ "Unknown input type", argument.position }); return false; @@ -1188,15 +932,7 @@ bool ValidateExecutableVisitor::validateInputValue( } } - auto itrKind = type.find(R"gql(kind)gql"); - - if (itrKind == type.end() || itrKind->second.type() != response::Type::EnumValue) - { - _errors.push_back({ "Unknown input type", argument.position }); - return false; - } - - auto kind = ModifiedArgument::convert(itrKind->second); + const auto kind = type->get().kind(); if (!argument.value) { @@ -1215,15 +951,15 @@ bool ValidateExecutableVisitor::validateInputValue( case introspection::TypeKind::NON_NULL: { // Unwrap and check the next one. - auto itrOfType = type.find(R"gql(ofType)gql"); + const auto ofType = getValidateType(type->get().ofType().lock()); - if (itrOfType == type.end() || itrOfType->second.type() != response::Type::Map) + if (!ofType) { _errors.push_back({ "Unknown Non-Null type", argument.position }); return false; } - return validateInputValue(hasNonNullDefaultValue, argument, itrOfType->second); + return validateInputValue(hasNonNullDefaultValue, argument, ofType); } case introspection::TypeKind::LIST: @@ -1234,9 +970,9 @@ bool ValidateExecutableVisitor::validateInputValue( return false; } - auto itrOfType = type.find(R"gql(ofType)gql"); + const auto ofType = getValidateType(type->get().ofType().lock()); - if (itrOfType == type.end() || itrOfType->second.type() != response::Type::Map) + if (!ofType) { _errors.push_back({ "Unknown List type", argument.position }); return false; @@ -1245,7 +981,7 @@ bool ValidateExecutableVisitor::validateInputValue( // Check every value against the target type. for (const auto& value : std::get(argument.value->data).values) { - if (!validateInputValue(false, value, itrOfType->second)) + if (!validateInputValue(false, value, ofType)) { // Error messages are added in the recursive call, so just bubble up the result. return false; @@ -1257,16 +993,14 @@ bool ValidateExecutableVisitor::validateInputValue( case introspection::TypeKind::INPUT_OBJECT: { - auto itrName = type.find(R"gql(name)gql"); + const auto name = type->get().name(); - if (itrName == type.end() || itrName->second.type() != response::Type::String) + if (name.empty()) { _errors.push_back({ "Unknown Input Object type", argument.position }); return false; } - const auto& name = itrName->second.get(); - if (!std::holds_alternative(argument.value->data)) { std::ostringstream message; @@ -1290,7 +1024,7 @@ bool ValidateExecutableVisitor::validateInputValue( } const auto& values = std::get(argument.value->data).values; - std::set subFields; + std::set subFields; // Check every value against the target type. for (const auto& entry : values) @@ -1332,10 +1066,7 @@ bool ValidateExecutableVisitor::validateInputValue( continue; } - auto itrFieldKind = entry.second.type.find(R"gql(kind)gql"); - - if (itrFieldKind == entry.second.type.end() - || itrFieldKind->second.type() != response::Type::EnumValue) + if (!entry.second.type) { std::ostringstream message; @@ -1346,8 +1077,7 @@ bool ValidateExecutableVisitor::validateInputValue( return false; } - auto fieldKind = - ModifiedArgument::convert(itrFieldKind->second); + const auto fieldKind = entry.second.type->get().kind(); if (fieldKind == introspection::TypeKind::NON_NULL) { @@ -1367,16 +1097,14 @@ bool ValidateExecutableVisitor::validateInputValue( case introspection::TypeKind::ENUM: { - auto itrName = type.find(R"gql(name)gql"); + const auto name = type->get().name(); - if (itrName == type.end() || itrName->second.type() != response::Type::String) + if (name.empty()) { _errors.push_back({ "Unknown Enum value", argument.position }); return false; } - const auto& name = itrName->second.get(); - if (!std::holds_alternative(argument.value->data)) { std::ostringstream message; @@ -1406,17 +1134,15 @@ bool ValidateExecutableVisitor::validateInputValue( case introspection::TypeKind::SCALAR: { - auto itrName = type.find(R"gql(name)gql"); + const auto name = type->get().name(); - if (itrName == type.end() || itrName->second.type() != response::Type::String) + if (name.empty()) { _errors.push_back({ "Unknown Scalar value", argument.position }); return false; } - const auto& name = itrName->second.get(); - - if (name == R"gql(Int)gql") + if (name == R"gql(Int)gql"sv) { if (!std::holds_alternative(argument.value->data)) { @@ -1424,7 +1150,7 @@ bool ValidateExecutableVisitor::validateInputValue( return false; } } - else if (name == R"gql(Float)gql") + else if (name == R"gql(Float)gql"sv) { if (!std::holds_alternative(argument.value->data) && !std::holds_alternative(argument.value->data)) @@ -1433,7 +1159,7 @@ bool ValidateExecutableVisitor::validateInputValue( return false; } } - else if (name == R"gql(String)gql") + else if (name == R"gql(String)gql"sv) { if (!std::holds_alternative(argument.value->data)) { @@ -1441,7 +1167,7 @@ bool ValidateExecutableVisitor::validateInputValue( return false; } } - else if (name == R"gql(ID)gql") + else if (name == R"gql(ID)gql"sv) { if (std::holds_alternative(argument.value->data)) { @@ -1461,7 +1187,7 @@ bool ValidateExecutableVisitor::validateInputValue( _errors.push_back({ "Expected ID value", argument.position }); return false; } - else if (name == R"gql(Boolean)gql") + else if (name == R"gql(Boolean)gql"sv) { if (!std::holds_alternative(argument.value->data)) { @@ -1495,52 +1221,34 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, const ValidateType& variableType, const schema_location& position, const ValidateType& inputType) { - if (variableType.type() != response::Type::Map) - { - _errors.push_back({ "Unknown variable type", position }); - return false; - } - - auto itrVariableKind = variableType.find(R"gql(kind)gql"); - - if (itrVariableKind == variableType.end() - || itrVariableKind->second.type() != response::Type::EnumValue) + if (!variableType) { _errors.push_back({ "Unknown variable type", position }); return false; } - auto variableKind = ModifiedArgument::convert(itrVariableKind->second); + const auto variableKind = variableType->get().kind(); if (variableKind == introspection::TypeKind::NON_NULL) { - auto itrVariableOfType = variableType.find(R"gql(ofType)gql"); + const auto ofType = getValidateType(variableType->get().ofType().lock()); - if (itrVariableOfType == variableType.end() - || itrVariableOfType->second.type() != response::Type::Map) + if (!ofType) { _errors.push_back({ "Unknown Non-Null variable type", position }); return false; } - return validateVariableType(true, itrVariableOfType->second, position, inputType); - } - - if (inputType.type() != response::Type::Map) - { - _errors.push_back({ "Unknown input type", position }); - return false; + return validateVariableType(true, ofType, position, inputType); } - auto itrInputKind = inputType.find(R"gql(kind)gql"); - - if (itrInputKind == inputType.end() || itrInputKind->second.type() != response::Type::EnumValue) + if (!inputType) { _errors.push_back({ "Unknown input type", position }); return false; } - auto inputKind = ModifiedArgument::convert(itrInputKind->second); + const auto inputKind = inputType->get().kind(); switch (inputKind) { @@ -1554,16 +1262,15 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, } // Unwrap and check the next one. - auto itrInputOfType = inputType.find(R"gql(ofType)gql"); + const auto ofType = getValidateType(inputType->get().ofType().lock()); - if (itrInputOfType == inputType.end() - || itrInputOfType->second.type() != response::Type::Map) + if (!ofType) { _errors.push_back({ "Unknown Non-Null input type", position }); return false; } - return validateVariableType(false, variableType, position, itrInputOfType->second); + return validateVariableType(false, variableType, position, ofType); } case introspection::TypeKind::LIST: @@ -1576,28 +1283,23 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, } // Unwrap and check the next one. - auto itrVariableOfType = variableType.find(R"gql(ofType)gql"); + const auto variableOfType = getValidateType(variableType->get().ofType().lock()); - if (itrVariableOfType == variableType.end() - || itrVariableOfType->second.type() != response::Type::Map) + if (!variableOfType) { _errors.push_back({ "Unknown List variable type", position }); return false; } - auto itrInputOfType = inputType.find(R"gql(ofType)gql"); + const auto inputOfType = getValidateType(inputType->get().ofType().lock()); - if (itrInputOfType == inputType.end() - || itrInputOfType->second.type() != response::Type::Map) + if (!inputOfType) { _errors.push_back({ "Unknown List input type", position }); return false; } - return validateVariableType(false, - itrVariableOfType->second, - position, - itrInputOfType->second); + return validateVariableType(false, variableOfType, position, inputOfType); } case introspection::TypeKind::INPUT_OBJECT: @@ -1644,27 +1346,22 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, } } - auto itrVariableName = variableType.find(R"gql(name)gql"); + const auto variableName = variableType->get().name(); - if (itrVariableName == variableType.end() - || itrVariableName->second.type() != response::Type::String) + if (variableName.empty()) { _errors.push_back({ "Unknown variable type", position }); return false; } - const auto& variableName = itrVariableName->second.get(); - - auto itrInputName = inputType.find(R"gql(name)gql"); + const auto inputName = inputType->get().name(); - if (itrInputName == inputType.end() || itrInputName->second.type() != response::Type::String) + if (inputName.empty()) { _errors.push_back({ "Unknown input type", position }); return false; } - const auto& inputName = itrInputName->second.get(); - if (variableName != inputName) { // http://spec.graphql.org/June2018/#sec-All-Variable-Usages-are-Allowed @@ -1682,275 +1379,112 @@ bool ValidateExecutableVisitor::validateVariableType(bool isNonNull, ValidateExecutableVisitor::TypeFields::const_iterator ValidateExecutableVisitor:: getScopedTypeFields() { - auto typeKind = getScopedTypeKind(); - auto itrType = _typeFields.find(_scopedType); + auto typeKind = _scopedType->get().kind(); + auto itrType = _typeFields.find(_scopedType->get().name()); - if (itrType == _typeFields.cend() && typeKind && !isScalarType(*typeKind)) + if (itrType == _typeFields.cend() && !isScalarType(typeKind)) { - std::ostringstream oss; - - oss << R"gql(query { - __type(name: ")gql" - << _scopedType << R"gql(") { - fields(includeDeprecated: true) { - name - type { - ...nestedType - } - args { - name - defaultValue - type { - ...nestedType - } - } - } - } - } + const auto& fields = _scopedType->get().fields(); + std::map validateFields; - fragment nestedType on __Type { - kind - name - ofType { - ...nestedType - } - })gql"; - - auto data = executeQuery(oss.str()); - auto members = data.release(); - auto itrResponse = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(__type)gql"; - }); - - if (itrResponse != members.end() && itrResponse->second.type() == response::Type::Map) + for (auto& entry : fields) { - std::map fields; - response::Value scalarKind(response::Type::EnumValue); - response::Value nonNullKind(response::Type::EnumValue); - - scalarKind.set(R"gql(SCALAR)gql"); - nonNullKind.set(R"gql(NON_NULL)gql"); - - members = itrResponse->second.release(); - itrResponse = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(fields)gql"; - }); - - if (itrResponse != members.end() && itrResponse->second.type() == response::Type::List) + if (!entry) { - auto entries = itrResponse->second.release(); - - for (auto& entry : entries) - { - if (entry.type() != response::Type::Map) - { - continue; - } - - members = entry.release(); - - auto itrFieldName = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(name)gql"; - }); - auto itrFieldType = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(type)gql"; - }); - - if (itrFieldName != members.end() - && itrFieldName->second.type() == response::Type::String - && itrFieldType != members.end() - && itrFieldType->second.type() == response::Type::Map) - { - auto fieldName = itrFieldName->second.release(); - ValidateTypeField subField; - - subField.returnType = std::move(itrFieldType->second); - - auto itrArgs = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(args)gql"; - }); - - if (itrArgs != members.end() - && itrArgs->second.type() == response::Type::List) - { - subField.arguments = - getArguments(itrArgs->second.release()); - } + continue; + } - fields[std::move(fieldName)] = std::move(subField); - } - } + const auto fieldName = entry->name(); + ValidateTypeField subField; - if (_scopedType == _operationTypes[strQuery]) - { - response::Value objectKind(response::Type::EnumValue); + subField.returnType = getValidateType(entry->type().lock()); - objectKind.set(R"gql(OBJECT)gql"); + if (fieldName.empty() || !subField.returnType) + { + continue; + } - ValidateTypeField schemaField; - response::Value schemaType(response::Type::Map); - response::Value notNullSchemaType(response::Type::Map); + subField.arguments = getArguments(entry->args()); - schemaType.emplace_back(R"gql(kind)gql", response::Value(objectKind)); - schemaType.emplace_back(R"gql(name)gql", response::Value(R"gql(__Schema)gql")); - notNullSchemaType.emplace_back(R"gql(kind)gql", response::Value(nonNullKind)); - notNullSchemaType.emplace_back(R"gql(ofType)gql", std::move(schemaType)); - schemaField.returnType = std::move(notNullSchemaType); - fields[R"gql(__schema)gql"] = std::move(schemaField); + validateFields[fieldName] = std::move(subField); + } - ValidateTypeField typeField; - response::Value typeType(response::Type::Map); + if (_schema->supportsIntrospection() && _scopedType == _operationTypes[strQuery]) + { + ValidateTypeField schemaField; - typeType.emplace_back(R"gql(kind)gql", response::Value(objectKind)); - typeType.emplace_back(R"gql(name)gql", response::Value(R"gql(__Type)gql")); - typeField.returnType = std::move(typeType); + schemaField.returnType = + getValidateType(_schema->WrapType(introspection::TypeKind::NON_NULL, + _schema->LookupType(R"gql(__Schema)gql"sv))); + validateFields[R"gql(__schema)gql"sv] = std::move(schemaField); - ValidateArgument nameArgument; - response::Value typeNameArg(response::Type::Map); - response::Value nonNullTypeNameArg(response::Type::Map); + ValidateTypeField typeField; + ValidateArgument nameArgument; - typeNameArg.emplace_back(R"gql(kind)gql", response::Value(scalarKind)); - typeNameArg.emplace_back(R"gql(name)gql", response::Value(R"gql(String)gql")); - nonNullTypeNameArg.emplace_back(R"gql(kind)gql", response::Value(nonNullKind)); - nonNullTypeNameArg.emplace_back(R"gql(ofType)gql", std::move(typeNameArg)); - nameArgument.type = std::move(nonNullTypeNameArg); + typeField.returnType = getValidateType(_schema->LookupType(R"gql(__Type)gql"sv)); - typeField.arguments[R"gql(name)gql"] = std::move(nameArgument); + nameArgument.type = getValidateType(_schema->WrapType(introspection::TypeKind::NON_NULL, + _schema->LookupType(R"gql(String)gql"sv))); + typeField.arguments[R"gql(name)gql"sv] = std::move(nameArgument); - fields[R"gql(__type)gql"] = std::move(typeField); - } - } + validateFields[R"gql(__type)gql"sv] = std::move(typeField); + } - ValidateTypeField typenameField; - response::Value typenameType(response::Type::Map); - response::Value notNullTypenameType(response::Type::Map); + ValidateTypeField typenameField; - typenameType.emplace_back(R"gql(kind)gql", response::Value(scalarKind)); - typenameType.emplace_back(R"gql(name)gql", response::Value(R"gql(String)gql")); - notNullTypenameType.emplace_back(R"gql(kind)gql", response::Value(nonNullKind)); - notNullTypenameType.emplace_back(R"gql(ofType)gql", std::move(typenameType)); - typenameField.returnType = std::move(notNullTypenameType); - fields[R"gql(__typename)gql"] = std::move(typenameField); + typenameField.returnType = + getValidateType(_schema->WrapType(introspection::TypeKind::NON_NULL, + _schema->LookupType(R"gql(String)gql"sv))); + validateFields[R"gql(__typename)gql"sv] = std::move(typenameField); - itrType = _typeFields.insert({ _scopedType, std::move(fields) }).first; - } + itrType = + _typeFields.insert({ _scopedType->get().name(), std::move(validateFields) }).first; } return itrType; } ValidateExecutableVisitor::InputTypeFields::const_iterator ValidateExecutableVisitor:: - getInputTypeFields(const std::string& name) + getInputTypeFields(std::string_view name) { - auto typeKind = getTypeKind(name); - auto itrType = _inputTypeFields.find(name); + auto itrFields = _inputTypeFields.find(name); - if (itrType == _inputTypeFields.cend() && typeKind - && *typeKind == introspection::TypeKind::INPUT_OBJECT) + if (itrFields == _inputTypeFields.cend()) { - std::ostringstream oss; - - oss << R"gql(query { - __type(name: ")gql" - << name << R"gql(") { - inputFields { - name - defaultValue - type { - ...nestedType - } - } - } - } - - fragment nestedType on __Type { - kind - name - ofType { - ...nestedType - } - })gql"; - - auto data = executeQuery(oss.str()); - auto members = data.release(); - auto itrResponse = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(__type)gql"; - }); + auto itrType = _types.find(name); - if (itrResponse != members.end() && itrResponse->second.type() == response::Type::Map) + if (itrType != _types.cend() + && itrType->second->get().kind() == introspection::TypeKind::INPUT_OBJECT) { - std::map fields; - - members = itrResponse->second.release(); - itrResponse = std::find_if(members.begin(), - members.end(), - [](const std::pair& entry) noexcept { - return entry.first == R"gql(inputFields)gql"; - }); - - if (itrResponse != members.end() && itrResponse->second.type() == response::Type::List) - { - itrType = _inputTypeFields - .insert({ name, - getArguments(itrResponse->second.release()) }) - .first; - } + itrFields = _inputTypeFields + .insert({ name, getArguments(itrType->second->get().inputFields()) }) + .first; } } - return itrType; + return itrFields; } template -std::string ValidateExecutableVisitor::getFieldType( - const _FieldTypes& fields, const std::string& name) +ValidateType ValidateExecutableVisitor::getFieldType( + const _FieldTypes& fields, std::string_view name) { - std::string result; auto itrType = fields.find(name); if (itrType == fields.end()) { - return result; + return ValidateType {}; } // Iteratively expand nested types till we get the underlying field type. - const std::string nameMember { R"gql(name)gql" }; - const std::string ofTypeMember { R"gql(ofType)gql" }; - auto itrName = getValidateFieldType(itrType->second).find(nameMember); - auto itrOfType = getValidateFieldType(itrType->second).find(ofTypeMember); - auto itrEnd = getValidateFieldType(itrType->second).end(); + auto fieldType = getValidateFieldType(itrType->second); - do + while (fieldType && fieldType->get().name().empty()) { - if (itrName != itrEnd && itrName->second.type() == response::Type::String) - { - result = itrName->second.template get(); - } - else if (itrOfType != itrEnd && itrOfType->second.type() == response::Type::Map) - { - itrEnd = itrOfType->second.end(); - itrName = itrOfType->second.find(nameMember); - itrOfType = itrOfType->second.find(ofTypeMember); - } - else - { - break; - } - } while (result.empty()); + fieldType = getValidateType(fieldType->get().ofType().lock()); + } - return result; + return fieldType; } const ValidateType& ValidateExecutableVisitor::getValidateFieldType( @@ -1966,59 +1500,17 @@ const ValidateType& ValidateExecutableVisitor::getValidateFieldType( } template -std::string ValidateExecutableVisitor::getWrappedFieldType( - const _FieldTypes& fields, const std::string& name) +ValidateType ValidateExecutableVisitor::getWrappedFieldType( + const _FieldTypes& fields, std::string_view name) { - std::string result; auto itrType = fields.find(name); if (itrType == fields.end()) { - return result; - } - - result = getWrappedFieldType(getValidateFieldType(itrType->second)); - - return result; -} - -std::string ValidateExecutableVisitor::getWrappedFieldType(const ValidateType& returnType) -{ - // Recursively expand nested types till we get the underlying field type. - const std::string nameMember { R"gql(name)gql" }; - auto itrName = returnType.find(nameMember); - auto itrEnd = returnType.end(); - - if (itrName != itrEnd && itrName->second.type() == response::Type::String) - { - return itrName->second.get(); - } - - std::ostringstream oss; - const std::string kindMember { R"gql(kind)gql" }; - const std::string ofTypeMember { R"gql(ofType)gql" }; - auto itrKind = returnType.find(kindMember); - auto itrOfType = returnType.find(ofTypeMember); - - if (itrKind != itrEnd && itrKind->second.type() == response::Type::EnumValue - && itrOfType != itrEnd && itrOfType->second.type() == response::Type::Map) - { - switch (ModifiedArgument::convert(itrKind->second)) - { - case introspection::TypeKind::LIST: - oss << '[' << getWrappedFieldType(itrOfType->second) << ']'; - break; - - case introspection::TypeKind::NON_NULL: - oss << getWrappedFieldType(itrOfType->second) << '!'; - break; - - default: - break; - } + return std::nullopt; } - return oss.str(); + return getValidateFieldType(itrType->second); } void ValidateExecutableVisitor::visitField(const peg::ast_node& field) @@ -2027,28 +1519,12 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) visitDirectives(introspection::DirectiveLocation::FIELD, child); }); - std::string name; + std::string_view name; peg::on_first_child(field, [&name](const peg::ast_node& child) { name = child.string_view(); }); - auto kind = getScopedTypeKind(); - - if (!kind) - { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections - auto position = field.begin(); - std::ostringstream message; - - message << "Field on unknown type: " << _scopedType << " name: " << name; - - _errors.push_back({ message.str(), { position.line, position.column } }); - return; - } - - std::string innerType; - std::string wrappedType; auto itrType = getScopedTypeFields(); if (itrType == _typeFields.cend()) @@ -2057,13 +1533,16 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) auto position = field.begin(); std::ostringstream message; - message << "Field on scalar type: " << _scopedType << " name: " << name; + message << "Field on scalar type: " << _scopedType->get().name() << " name: " << name; _errors.push_back({ message.str(), { position.line, position.column } }); return; } - switch (*kind) + ValidateType innerType; + ValidateType wrappedType; + + switch (_scopedType->get().kind()) { case introspection::TypeKind::OBJECT: case introspection::TypeKind::INTERFACE: @@ -2082,15 +1561,17 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) auto position = field.begin(); std::ostringstream message; - message << "Field on union type: " << _scopedType << " name: " << name; + message << "Field on union type: " << _scopedType->get().name() + << " name: " << name; _errors.push_back({ message.str(), { position.line, position.column } }); return; } // http://spec.graphql.org/June2018/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types - innerType = "String"; - wrappedType = "String!"; + innerType = getValidateType(_schema->LookupType("String"sv)); + wrappedType = getValidateType( + _schema->WrapType(introspection::TypeKind::NON_NULL, getSharedType(innerType))); break; } @@ -2098,19 +1579,19 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) break; } - if (innerType.empty()) + if (!innerType) { // http://spec.graphql.org/June2018/#sec-Field-Selections-on-Objects-Interfaces-and-Unions-Types auto position = field.begin(); std::ostringstream message; - message << "Undefined field type: " << _scopedType << " name: " << name; + message << "Undefined field type: " << _scopedType->get().name() << " name: " << name; _errors.push_back({ message.str(), { position.line, position.column } }); return; } - std::string alias; + std::string_view alias; peg::on_first_child(field, [&alias](const peg::ast_node& child) { alias = child.string_view(); @@ -2122,15 +1603,15 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) } ValidateFieldArguments validateArguments; - std::map argumentLocations; - std::queue argumentNames; + std::map argumentLocations; + std::vector argumentNames; peg::on_first_child(field, [this, &name, &validateArguments, &argumentLocations, &argumentNames]( const peg::ast_node& child) { for (auto& argument : child.children) { - auto argumentName = argument->children.front()->string(); + auto argumentName = argument->children.front()->string_view(); auto position = argument->begin(); if (validateArguments.find(argumentName) != validateArguments.end()) @@ -2138,8 +1619,8 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) // http://spec.graphql.org/June2018/#sec-Argument-Uniqueness std::ostringstream message; - message << "Conflicting argument type: " << _scopedType << " field: " << name - << " name: " << argumentName; + message << "Conflicting argument type: " << _scopedType->get().name() + << " field: " << name << " name: " << argumentName; _errors.push_back({ message.str(), { position.line, position.column } }); continue; @@ -2150,12 +1631,13 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) visitor.visit(*argument->children.back()); validateArguments[argumentName] = visitor.getArgumentValue(); argumentLocations[argumentName] = { position.line, position.column }; - argumentNames.push(std::move(argumentName)); + argumentNames.push_back(argumentName); } }); - std::optional objectType = - (*kind == introspection::TypeKind::OBJECT ? std::make_optional(_scopedType) : std::nullopt); + ValidateType objectType = + (_scopedType->get().kind() == introspection::TypeKind::OBJECT ? _scopedType + : ValidateType {}); ValidateField validateField(std::move(wrappedType), std::move(objectType), name, @@ -2175,7 +1657,7 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) auto position = field.begin(); std::ostringstream message; - message << "Conflicting field type: " << _scopedType << " name: " << name; + message << "Conflicting field type: " << _scopedType->get().name() << " name: " << name; _errors.push_back({ message.str(), { position.line, position.column } }); } @@ -2185,12 +1667,8 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) if (itrField != itrType->second.end()) { - while (!argumentNames.empty()) + for (auto argumentName : argumentNames) { - auto argumentName = std::move(argumentNames.front()); - - argumentNames.pop(); - auto itrArgument = itrField->second.arguments.find(argumentName); if (itrArgument == itrField->second.arguments.end()) @@ -2198,8 +1676,8 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) // http://spec.graphql.org/June2018/#sec-Argument-Names std::ostringstream message; - message << "Undefined argument type: " << _scopedType << " field: " << name - << " name: " << argumentName; + message << "Undefined argument type: " << _scopedType->get().name() + << " field: " << name << " name: " << argumentName; _errors.push_back({ message.str(), argumentLocations[argumentName] }); } @@ -2220,8 +1698,8 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) // http://spec.graphql.org/June2018/#sec-Values-of-Correct-Type std::ostringstream message; - message << "Incompatible argument type: " << _scopedType << " field: " << name - << " name: " << argument.first; + message << "Incompatible argument type: " << _scopedType->get().name() + << " field: " << name << " name: " << argument.first; _errors.push_back({ message.str(), argumentLocations[argument.first] }); } @@ -2235,12 +1713,8 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) } // See if the argument is wrapped in NON_NULL - auto itrKind = argument.second.type.find(R"gql(kind)gql"); - - if (itrKind != argument.second.type.end() - && itrKind->second.type() == response::Type::EnumValue - && introspection::TypeKind::NON_NULL - == ModifiedArgument::convert(itrKind->second)) + if (argument.second.type + && introspection::TypeKind::NON_NULL == argument.second.type->get().kind()) { // http://spec.graphql.org/June2018/#sec-Required-Arguments auto position = field.begin(); @@ -2248,14 +1722,15 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) message << (missing ? "Missing argument type: " : "Required non-null argument type: ") - << _scopedType << " field: " << name << " name: " << argument.first; + << _scopedType->get().name() << " field: " << name + << " name: " << argument.first; _errors.push_back({ message.str(), { position.line, position.column } }); } } } - _selectionFields.insert({ std::move(alias), std::move(validateField) }); + _selectionFields.insert({ alias, std::move(validateField) }); const peg::ast_node* selection = nullptr; @@ -2284,21 +1759,16 @@ void ValidateExecutableVisitor::visitField(const peg::ast_node& field) _fieldCount = outerFieldCount; } - if (subFieldCount == 0) + if (subFieldCount == 0 && !isScalarType(innerType->get().kind())) { - auto itrInnerKind = _typeKinds.find(innerType); - - if (itrInnerKind != _typeKinds.end() && !isScalarType(itrInnerKind->second)) - { - // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections - auto position = field.begin(); - std::ostringstream message; + // http://spec.graphql.org/June2018/#sec-Leaf-Field-Selections + auto position = field.begin(); + std::ostringstream message; - message << "Missing fields on non-scalar type: " << innerType; + message << "Missing fields on non-scalar type: " << innerType->get().name(); - _errors.push_back({ message.str(), { position.line, position.column } }); - return; - } + _errors.push_back({ message.str(), { position.line, position.column } }); + return; } ++_fieldCount; @@ -2310,7 +1780,7 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen visitDirectives(introspection::DirectiveLocation::FRAGMENT_SPREAD, child); }); - const std::string name(fragmentSpread.children.front()->string_view()); + const auto name = fragmentSpread.children.front()->string_view(); auto itr = _fragmentDefinitions.find(name); if (itr == _fragmentDefinitions.cend()) @@ -2343,9 +1813,10 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen const auto& selection = *itr->second.children.back(); const auto& typeCondition = itr->second.children[1]; - std::string innerType { typeCondition->children.front()->string_view() }; + const auto innerType = typeCondition->children.front()->string_view(); + const auto itrInner = _types.find(innerType); - if (!matchesScopedType(innerType)) + if (itrInner == _types.cend() || !matchesScopedType(innerType)) { // http://spec.graphql.org/June2018/#sec-Fragment-spread-is-possible auto position = fragmentSpread.begin(); @@ -2360,7 +1831,7 @@ void ValidateExecutableVisitor::visitFragmentSpread(const peg::ast_node& fragmen auto outerType = std::move(_scopedType); _fragmentStack.insert(name); - _scopedType = std::move(innerType); + _scopedType = itrInner->second; visitSelection(selection); @@ -2376,46 +1847,50 @@ void ValidateExecutableVisitor::visitInlineFragment(const peg::ast_node& inlineF visitDirectives(introspection::DirectiveLocation::INLINE_FRAGMENT, child); }); - std::string innerType; + std::string_view innerType; schema_location typeConditionLocation; peg::on_first_child(inlineFragment, [&innerType, &typeConditionLocation](const peg::ast_node& child) { auto position = child.begin(); - innerType = child.children.front()->string(); + innerType = child.children.front()->string_view(); typeConditionLocation = { position.line, position.column }; }); + ValidateType fragmentType; + if (innerType.empty()) { - innerType = _scopedType; + fragmentType = _scopedType; } else { - auto itrKind = _typeKinds.find(innerType); + auto itrInner = _types.find(innerType); - if (itrKind == _typeKinds.end() || isScalarType(itrKind->second)) + if (itrInner == _types.end()) { // http://spec.graphql.org/June2018/#sec-Fragment-Spread-Type-Existence - // http://spec.graphql.org/June2018/#sec-Fragments-On-Composite-Types std::ostringstream message; - message << (itrKind == _typeKinds.end() - ? "Undefined target type on inline fragment name: " - : "Scalar target type on inline fragment name: ") - << innerType; + message << "Undefined target type on inline fragment name: " << innerType; _errors.push_back({ message.str(), std::move(typeConditionLocation) }); return; } - if (!matchesScopedType(innerType)) + fragmentType = itrInner->second; + + if (isScalarType(fragmentType->get().kind()) || !matchesScopedType(innerType)) { + // http://spec.graphql.org/June2018/#sec-Fragments-On-Composite-Types // http://spec.graphql.org/June2018/#sec-Fragment-spread-is-possible std::ostringstream message; - message << "Incompatible target type on inline fragment name: " << innerType; + message << (isScalarType(fragmentType->get().kind()) + ? "Scalar target type on inline fragment name: " + : "Incompatible target type on inline fragment name: ") + << innerType; _errors.push_back({ message.str(), std::move(typeConditionLocation) }); return; @@ -2423,10 +1898,10 @@ void ValidateExecutableVisitor::visitInlineFragment(const peg::ast_node& inlineF } peg::on_first_child(inlineFragment, - [this, &innerType](const peg::ast_node& selection) { + [this, &fragmentType](const peg::ast_node& selection) { auto outerType = std::move(_scopedType); - _scopedType = std::move(innerType); + _scopedType = std::move(fragmentType); visitSelection(selection); @@ -2437,11 +1912,11 @@ void ValidateExecutableVisitor::visitInlineFragment(const peg::ast_node& inlineF void ValidateExecutableVisitor::visitDirectives( introspection::DirectiveLocation location, const peg::ast_node& directives) { - std::set uniqueDirectives; + std::set uniqueDirectives; for (const auto& directive : directives.children) { - std::string directiveName; + std::string_view directiveName; peg::on_first_child(*directive, [&directiveName](const peg::ast_node& child) { @@ -2523,13 +1998,13 @@ void ValidateExecutableVisitor::visitDirectives( peg::on_first_child(*directive, [this, &directive, &directiveName, itrDirective](const peg::ast_node& child) { ValidateFieldArguments validateArguments; - std::map argumentLocations; - std::queue argumentNames; + std::map argumentLocations; + std::vector argumentNames; for (auto& argument : child.children) { auto position = argument->begin(); - auto argumentName = argument->children.front()->string(); + auto argumentName = argument->children.front()->string_view(); if (validateArguments.find(argumentName) != validateArguments.end()) { @@ -2548,15 +2023,11 @@ void ValidateExecutableVisitor::visitDirectives( visitor.visit(*argument->children.back()); validateArguments[argumentName] = visitor.getArgumentValue(); argumentLocations[argumentName] = { position.line, position.column }; - argumentNames.push(std::move(argumentName)); + argumentNames.push_back(argumentName); } - while (!argumentNames.empty()) + for (auto argumentName : argumentNames) { - auto argumentName = std::move(argumentNames.front()); - - argumentNames.pop(); - auto itrArgument = itrDirective->second.arguments.find(argumentName); if (itrArgument == itrDirective->second.arguments.end()) @@ -2601,12 +2072,8 @@ void ValidateExecutableVisitor::visitDirectives( } // See if the argument is wrapped in NON_NULL - auto itrKind = argument.second.type.find(R"gql(kind)gql"); - - if (itrKind != argument.second.type.end() - && itrKind->second.type() == response::Type::EnumValue - && introspection::TypeKind::NON_NULL - == ModifiedArgument::convert(itrKind->second)) + if (argument.second.type + && introspection::TypeKind::NON_NULL == argument.second.type->get().kind()) { // http://spec.graphql.org/June2018/#sec-Required-Arguments auto position = directive->begin(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 40ebf705..6d4204c7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,6 +23,15 @@ target_link_libraries(today_tests PRIVATE add_bigobj_flag(today_tests) gtest_add_tests(TARGET today_tests) +add_executable(nointrospection_tests NoIntrospectionTests.cpp) +target_link_libraries(nointrospection_tests PRIVATE + unifiedgraphql_nointrospection + graphqljson + GTest::GTest + GTest::Main) +add_bigobj_flag(nointrospection_tests) +gtest_add_tests(TARGET nointrospection_tests) + add_executable(argument_tests ArgumentTests.cpp) target_link_libraries(argument_tests PRIVATE unifiedgraphql @@ -53,7 +62,8 @@ target_include_directories(response_tests PUBLIC gtest_add_tests(TARGET response_tests) if(WIN32 AND BUILD_SHARED_LIBS) - add_custom_target(copy_test_dlls ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + add_custom_target(copy_test_dlls ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} COMMAND ${CMAKE_COMMAND} -E copy $ ${CMAKE_CURRENT_BINARY_DIR} @@ -62,6 +72,7 @@ if(WIN32 AND BUILD_SHARED_LIBS) add_dependencies(validation_tests copy_test_dlls) add_dependencies(today_tests copy_test_dlls) + add_dependencies(nointrospection_tests copy_test_dlls) add_dependencies(argument_tests copy_test_dlls) add_dependencies(pegtl_tests copy_test_dlls) add_dependencies(response_tests copy_test_dlls) diff --git a/test/NoIntrospectionTests.cpp b/test/NoIntrospectionTests.cpp new file mode 100644 index 00000000..cc052530 --- /dev/null +++ b/test/NoIntrospectionTests.cpp @@ -0,0 +1,243 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +#include + +#include "TodayMock.h" + +#include "graphqlservice/JSONResponse.h" + +#include + +using namespace graphql; + +using namespace std::literals; + + +// this is similar to TodayTests, will trust QueryEverything works +// and then check if introspection is disabled + +class NoIntrospectionServiceCase : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + std::string fakeAppointmentId("fakeAppointmentId"); + _fakeAppointmentId.resize(fakeAppointmentId.size()); + std::copy(fakeAppointmentId.cbegin(), fakeAppointmentId.cend(), _fakeAppointmentId.begin()); + + std::string fakeTaskId("fakeTaskId"); + _fakeTaskId.resize(fakeTaskId.size()); + std::copy(fakeTaskId.cbegin(), fakeTaskId.cend(), _fakeTaskId.begin()); + + std::string fakeFolderId("fakeFolderId"); + _fakeFolderId.resize(fakeFolderId.size()); + std::copy(fakeFolderId.cbegin(), fakeFolderId.cend(), _fakeFolderId.begin()); + + auto query = std::make_shared( + []() -> std::vector> + { + ++_getAppointmentsCount; + return { std::make_shared(response::IdType(_fakeAppointmentId), "tomorrow", "Lunch?", false) }; + }, []() -> std::vector> + { + ++_getTasksCount; + return { std::make_shared(response::IdType(_fakeTaskId), "Don't forget", true) }; + }, []() -> std::vector> + { + ++_getUnreadCountsCount; + return { std::make_shared(response::IdType(_fakeFolderId), "\"Fake\" Inbox", 3) }; + }); + auto mutation = std::make_shared( + [](today::CompleteTaskInput&& input) -> std::shared_ptr + { + return std::make_shared( + std::make_shared(std::move(input.id), "Mutated Task!", *(input.isComplete)), + std::move(input.clientMutationId) + ); + }); + auto subscription = std::make_shared( + [](const std::shared_ptr&) -> std::shared_ptr + { + return { std::make_shared(response::IdType(_fakeAppointmentId), "tomorrow", "Lunch?", true) }; + }); + + _service = std::make_shared(query, mutation, subscription); + } + + static void TearDownTestCase() + { + _fakeAppointmentId.clear(); + _fakeTaskId.clear(); + _fakeFolderId.clear(); + _service.reset(); + } + +protected: + static response::IdType _fakeAppointmentId; + static response::IdType _fakeTaskId; + static response::IdType _fakeFolderId; + + static std::shared_ptr _service; + static size_t _getAppointmentsCount; + static size_t _getTasksCount; + static size_t _getUnreadCountsCount; +}; + +response::IdType NoIntrospectionServiceCase::_fakeAppointmentId; +response::IdType NoIntrospectionServiceCase::_fakeTaskId; +response::IdType NoIntrospectionServiceCase::_fakeFolderId; + +std::shared_ptr NoIntrospectionServiceCase::_service; +size_t NoIntrospectionServiceCase::_getAppointmentsCount = 0; +size_t NoIntrospectionServiceCase::_getTasksCount = 0; +size_t NoIntrospectionServiceCase::_getUnreadCountsCount = 0; +size_t today::NextAppointmentChange::_notifySubscribeCount = 0; +size_t today::NextAppointmentChange::_subscriptionCount = 0; +size_t today::NextAppointmentChange::_notifyUnsubscribeCount = 0; + +TEST_F(NoIntrospectionServiceCase, QueryEverything) +{ + auto query = R"( + query Everything { + appointments { + edges { + node { + id + subject + when + isNow + __typename + } + } + } + tasks { + edges { + node { + id + title + isComplete + __typename + } + } + } + unreadCounts { + edges { + node { + id + name + unreadCount + __typename + } + } + } + })"_graphql; + response::Value variables(response::Type::Map); + auto state = std::make_shared(1); + auto result = _service->resolve(std::launch::async, state, query, "Everything", std::move(variables)).get(); + EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; + EXPECT_EQ(size_t(1), _getTasksCount) << "today service lazy loads the tasks and caches the result"; + EXPECT_EQ(size_t(1), _getUnreadCountsCount) << "today service lazy loads the unreadCounts and caches the result"; + EXPECT_EQ(size_t(1), state->appointmentsRequestId) << "today service passed the same RequestState"; + EXPECT_EQ(size_t(1), state->tasksRequestId) << "today service passed the same RequestState"; + EXPECT_EQ(size_t(1), state->unreadCountsRequestId) << "today service passed the same RequestState"; + EXPECT_EQ(size_t(1), state->loadAppointmentsCount) << "today service called the loader once"; + EXPECT_EQ(size_t(1), state->loadTasksCount) << "today service called the loader once"; + EXPECT_EQ(size_t(1), state->loadUnreadCountsCount) << "today service called the loader once"; + + try + { + ASSERT_TRUE(result.type() == response::Type::Map); + auto errorsItr = result.find("errors"); + if (errorsItr != result.get().cend()) + { + FAIL() << response::toJSON(response::Value(errorsItr->second)); + } + const auto data = service::ScalarArgument::require("data", result); + + const auto appointments = service::ScalarArgument::require("appointments", data); + const auto appointmentEdges = service::ScalarArgument::require("edges", appointments); + ASSERT_EQ(1, appointmentEdges.size()) << "appointments should have 1 entry"; + ASSERT_TRUE(appointmentEdges[0].type() == response::Type::Map) << "appointment should be an object"; + const auto appointmentNode = service::ScalarArgument::require("node", appointmentEdges[0]); + EXPECT_EQ(_fakeAppointmentId, service::IdArgument::require("id", appointmentNode)) << "id should match in base64 encoding"; + EXPECT_EQ("Lunch?", service::StringArgument::require("subject", appointmentNode)) << "subject should match"; + EXPECT_EQ("tomorrow", service::StringArgument::require("when", appointmentNode)) << "when should match"; + EXPECT_FALSE(service::BooleanArgument::require("isNow", appointmentNode)) << "isNow should match"; + EXPECT_EQ("Appointment", service::StringArgument::require("__typename", appointmentNode)) << "__typename should match"; + + const auto tasks = service::ScalarArgument::require("tasks", data); + const auto taskEdges = service::ScalarArgument::require("edges", tasks); + ASSERT_EQ(1, taskEdges.size()) << "tasks should have 1 entry"; + ASSERT_TRUE(taskEdges[0].type() == response::Type::Map) << "task should be an object"; + const auto taskNode = service::ScalarArgument::require("node", taskEdges[0]); + EXPECT_EQ(_fakeTaskId, service::IdArgument::require("id", taskNode)) << "id should match in base64 encoding"; + EXPECT_EQ("Don't forget", service::StringArgument::require("title", taskNode)) << "title should match"; + EXPECT_TRUE(service::BooleanArgument::require("isComplete", taskNode)) << "isComplete should match"; + EXPECT_EQ("Task", service::StringArgument::require("__typename", taskNode)) << "__typename should match"; + + const auto unreadCounts = service::ScalarArgument::require("unreadCounts", data); + const auto unreadCountEdges = service::ScalarArgument::require("edges", unreadCounts); + ASSERT_EQ(1, unreadCountEdges.size()) << "unreadCounts should have 1 entry"; + ASSERT_TRUE(unreadCountEdges[0].type() == response::Type::Map) << "unreadCount should be an object"; + const auto unreadCountNode = service::ScalarArgument::require("node", unreadCountEdges[0]); + EXPECT_EQ(_fakeFolderId, service::IdArgument::require("id", unreadCountNode)) << "id should match in base64 encoding"; + EXPECT_EQ("\"Fake\" Inbox", service::StringArgument::require("name", unreadCountNode)) << "name should match"; + EXPECT_EQ(3, service::IntArgument::require("unreadCount", unreadCountNode)) << "unreadCount should match"; + EXPECT_EQ("Folder", service::StringArgument::require("__typename", unreadCountNode)) << "__typename should match"; + } + catch (service::schema_exception & ex) + { + FAIL() << response::toJSON(ex.getErrors()); + } +} + +TEST_F(NoIntrospectionServiceCase, NoSchema) +{ + auto query = R"(query { + __schema { + queryType { name } + } + })"_graphql; + response::Value variables(response::Type::Map); + auto future = _service->resolve(std::launch::deferred, nullptr, query, "", std::move(variables)); + auto result = future.get(); + + try + { + ASSERT_TRUE(result.type() == response::Type::Map); + auto errorsItr = result.find("errors"); + ASSERT_FALSE(errorsItr == result.get().cend()); + auto errorsString = response::toJSON(response::Value(errorsItr->second)); + EXPECT_EQ(R"js([{"message":"Undefined field type: Query name: __schema","locations":[{"line":2,"column":4}]}])js", errorsString) << "error should match"; + } + catch (service::schema_exception & ex) + { + FAIL() << response::toJSON(ex.getErrors()); + } +} + +TEST_F(NoIntrospectionServiceCase, NoType) +{ + auto query = R"(query { + __type(name: "Query") { + description + } + })"_graphql; + response::Value variables(response::Type::Map); + auto future = _service->resolve(std::launch::deferred, nullptr, query, "", std::move(variables)); + auto result = future.get(); + + try + { + ASSERT_TRUE(result.type() == response::Type::Map); + auto errorsItr = result.find("errors"); + ASSERT_FALSE(errorsItr == result.get().cend()); + auto errorsString = response::toJSON(response::Value(errorsItr->second)); + EXPECT_EQ(R"js([{"message":"Undefined field type: Query name: __type","locations":[{"line":2,"column":4}]}])js", errorsString) << "error should match"; + } + catch (service::schema_exception & ex) + { + FAIL() << response::toJSON(ex.getErrors()); + } +} diff --git a/test/TodayTests.cpp b/test/TodayTests.cpp index f695c3bd..47f15841 100644 --- a/test/TodayTests.cpp +++ b/test/TodayTests.cpp @@ -238,6 +238,64 @@ TEST_F(TodayServiceCase, QueryAppointments) } } +TEST_F(TodayServiceCase, QueryAppointmentsWithForceError) +{ + auto query = R"({ + appointments { + edges { + node { + appointmentId: id + subject + when + isNow + forceError + } + } + } + })"_graphql; + response::Value variables(response::Type::Map); + auto state = std::make_shared(2); + auto result = _service->resolve(state, query, "", std::move(variables)).get(); + EXPECT_EQ(size_t(1), _getAppointmentsCount) << "today service lazy loads the appointments and caches the result"; + EXPECT_GE(size_t(1), _getTasksCount) << "today service lazy loads the tasks and caches the result"; + EXPECT_GE(size_t(1), _getUnreadCountsCount) << "today service lazy loads the unreadCounts and caches the result"; + EXPECT_EQ(size_t(2), state->appointmentsRequestId) << "today service passed the same RequestState"; + EXPECT_EQ(size_t(0), state->tasksRequestId) << "today service did not call the loader"; + EXPECT_EQ(size_t(0), state->unreadCountsRequestId) << "today service did not call the loader"; + EXPECT_EQ(size_t(1), state->loadAppointmentsCount) << "today service called the loader once"; + EXPECT_EQ(size_t(0), state->loadTasksCount) << "today service did not call the loader"; + EXPECT_EQ(size_t(0), state->loadUnreadCountsCount) << "today service did not call the loader"; + + try + { + ASSERT_TRUE(result.type() == response::Type::Map); + auto errorsItr = result.find("errors"); + if (errorsItr == result.get().cend()) + { + FAIL() << response::toJSON(response::Value(result)) << "no errors returned"; + } + + auto errorsString = response::toJSON(response::Value(errorsItr->second)); + EXPECT_EQ(R"js([{"message":"Field error name: forceError unknown error: this error was forced","locations":[{"line":9,"column":7}],"path":["appointments","edges",0,"node","forceError"]}])js", errorsString) << "error should match"; + + const auto data = service::ScalarArgument::require("data", result); + + const auto appointments = service::ScalarArgument::require("appointments", data); + const auto appointmentEdges = service::ScalarArgument::require("edges", appointments); + ASSERT_EQ(1, appointmentEdges.size()) << "appointments should have 1 entry"; + ASSERT_TRUE(appointmentEdges[0].type() == response::Type::Map) << "appointment should be an object"; + const auto appointmentNode = service::ScalarArgument::require("node", appointmentEdges[0]); + EXPECT_EQ(_fakeAppointmentId, service::IdArgument::require("appointmentId", appointmentNode)) << "id should match in base64 encoding"; + EXPECT_EQ("Lunch?", service::StringArgument::require("subject", appointmentNode)) << "subject should match"; + EXPECT_EQ("tomorrow", service::StringArgument::require("when", appointmentNode)) << "when should match"; + EXPECT_FALSE(service::BooleanArgument::require("isNow", appointmentNode)) << "isNow should match"; + } + catch (service::schema_exception & ex) + { + FAIL() << response::toJSON(ex.getErrors()); + } +} + TEST_F(TodayServiceCase, QueryTasks) { auto query = R"gql({